use alloc::boxed::Box;
use alloc::sync::Weak;
use alloc::vec::Vec;
#[cfg(feature = "stable_polyfill")]
use ascii::AsAsciiStr;
use crate::ioctl::DrmCardDevice;
use super::{BlobId, PropertyId};
#[derive(Debug)]
pub struct ModeProp {
pub prop_id: PropertyId,
pub value: u64,
}
#[derive(Debug)]
#[non_exhaustive]
#[repr(u32)]
pub enum PropertyType {
Unknown = 0,
Range = crate::ioctl::DRM_MODE_PROP_RANGE,
Enum = crate::ioctl::DRM_MODE_PROP_ENUM,
Blob = crate::ioctl::DRM_MODE_PROP_BLOB,
Bitmask = crate::ioctl::DRM_MODE_PROP_BITMASK,
Object = crate::ioctl::DRM_MODE_PROP_OBJECT,
SignedRange = crate::ioctl::DRM_MODE_PROP_SIGNED_RANGE,
}
impl PropertyType {
pub fn from_raw_flags(flags: u32) -> (Self, bool) {
let immutable = (flags & crate::ioctl::DRM_MODE_PROP_IMMUTABLE) != 0;
let type_raw = flags
& (crate::ioctl::DRM_MODE_PROP_LEGACY_TYPE | crate::ioctl::DRM_MODE_PROP_EXTENDED_TYPE);
let typ = match type_raw {
crate::ioctl::DRM_MODE_PROP_RANGE => Self::Range,
crate::ioctl::DRM_MODE_PROP_ENUM => Self::Enum,
crate::ioctl::DRM_MODE_PROP_BLOB => Self::Blob,
crate::ioctl::DRM_MODE_PROP_BITMASK => Self::Bitmask,
crate::ioctl::DRM_MODE_PROP_OBJECT => Self::Object,
crate::ioctl::DRM_MODE_PROP_SIGNED_RANGE => Self::SignedRange,
_ => Self::Unknown,
};
(typ, immutable)
}
}
#[derive(Debug)]
pub struct ObjectPropMeta<'card> {
pub(crate) raw: crate::ioctl::DrmModeGetProperty,
pub(crate) card: &'card crate::Card,
}
impl<'card> ObjectPropMeta<'card> {
#[inline(always)]
pub(crate) fn new(raw: crate::ioctl::DrmModeGetProperty, card: &'card crate::Card) -> Self {
Self { raw, card }
}
#[inline]
pub fn property_id(&self) -> PropertyId {
PropertyId(self.raw.prop_id)
}
pub fn name(&self) -> &str {
let raw = &self.raw.name[..];
let raw = raw.split(|c| *c == 0).next().unwrap();
#[cfg(feature = "stable_polyfill")]
return raw.as_ascii_str().expect("non-ascii name?!").as_str();
#[cfg(not(feature = "stable_polyfill"))]
{
let raw = unsafe { raw.as_ascii_unchecked() };
return raw.as_str();
}
}
#[inline]
pub fn property_type(&self) -> PropertyType {
let (ret, _) = PropertyType::from_raw_flags(self.raw.flags);
ret
}
#[inline]
pub fn is_immutable(&self) -> bool {
let (_, immut) = PropertyType::from_raw_flags(self.raw.flags);
immut
}
#[inline]
pub fn is_mutable(&self) -> bool {
!self.is_immutable()
}
pub fn range(&self) -> Result<(u64, u64), crate::Error> {
const RANGE_TYPES: u32 =
crate::ioctl::DRM_MODE_PROP_RANGE | crate::ioctl::DRM_MODE_PROP_SIGNED_RANGE;
let is_range = (self.raw.flags & RANGE_TYPES) != 0;
if !is_range {
return Err(crate::Error::NotSupported);
}
if self.raw.count_values() != 2 {
return Err(crate::Error::RemoteFailure);
}
let mut pair = [0_u64; 2];
let mut tmp = crate::ioctl::DrmModeGetProperty::zeroed();
tmp.prop_id = self.raw.prop_id;
unsafe { tmp.set_values_ptr(&mut pair as *mut u64, 2) };
self.card
.ioctl(crate::ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)
.unwrap();
if tmp.count_values() != 2 {
return Err(crate::Error::RemoteFailure);
}
Ok((pair[0], pair[1]))
}
pub fn values(&self) -> Result<Vec<u64>, crate::Error> {
let mut count = self.raw.count_values() as usize;
if count == 0 {
return Ok(Vec::new());
}
loop {
let mut values = crate::vec_with_capacity::<u64>(count)?;
let mut tmp = crate::ioctl::DrmModeGetProperty::zeroed();
tmp.prop_id = self.raw.prop_id;
unsafe { tmp.set_values_ptr(values.as_mut_ptr(), count as u32) };
self.card
.ioctl(crate::ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)
.unwrap();
let new_count = tmp.count_values() as usize;
if new_count != count {
count = new_count;
continue;
}
unsafe {
values.set_len(count);
}
return Ok(values);
}
}
pub fn enum_members(&self) -> Result<Vec<ObjectPropEnumMember>, crate::Error> {
const ENUM_TYPES: u32 =
crate::ioctl::DRM_MODE_PROP_ENUM | crate::ioctl::DRM_MODE_PROP_BITMASK;
let is_enum = (self.raw.flags & ENUM_TYPES) != 0;
if !is_enum {
return Ok(Vec::new());
}
let mut count = self.raw.count_enum_blobs() as usize;
loop {
let mut members = crate::vec_with_capacity::<ObjectPropEnumMember>(count)?;
let mut tmp = crate::ioctl::DrmModeGetProperty::zeroed();
tmp.prop_id = self.raw.prop_id;
unsafe {
tmp.set_enum_blob_ptr(
members.as_mut_ptr() as *mut crate::ioctl::DrmModePropertyEnum,
count as u32,
)
};
self.card
.ioctl(crate::ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)
.unwrap();
let new_count = tmp.count_enum_blobs() as usize;
if new_count != count {
count = new_count;
continue;
}
unsafe {
members.set_len(count);
}
return Ok(members);
}
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct ObjectPropEnumMember {
raw: crate::ioctl::DrmModePropertyEnum,
}
impl ObjectPropEnumMember {
#[inline]
pub fn value(&self) -> u64 {
self.raw.value
}
pub fn name(&self) -> &str {
let raw = &self.raw.name[..];
let raw = raw.split(|c| *c == 0).next().unwrap();
#[cfg(feature = "stable_polyfill")]
return raw.as_ascii_str().expect("non-ascii name?!").as_str();
#[cfg(not(feature = "stable_polyfill"))]
{
let raw = raw.as_ascii().unwrap();
return raw.as_str();
}
}
}
pub trait AsRawPropertyValue {
fn as_raw_property_value(&self) -> u64;
}
pub trait IntoRawPropertyValue: AsRawPropertyValue {
fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>);
}
macro_rules! trivial_as_property_value {
($t:ty) => {
impl AsRawPropertyValue for $t {
#[inline(always)]
fn as_raw_property_value(&self) -> u64 {
*self as u64
}
}
impl IntoRawPropertyValue for $t {
#[inline(always)]
fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>) {
(self as u64, None)
}
}
};
}
trivial_as_property_value!(u64);
trivial_as_property_value!(u32);
trivial_as_property_value!(u16);
trivial_as_property_value!(u8);
trivial_as_property_value!(usize);
trivial_as_property_value!(i64);
trivial_as_property_value!(i32);
trivial_as_property_value!(i16);
trivial_as_property_value!(i8);
trivial_as_property_value!(isize);
trivial_as_property_value!(bool);
#[derive(Debug)]
pub struct BlobHandle {
pub(crate) id: Option<BlobId>,
pub(crate) f: Weak<linux_io::File<DrmCardDevice>>,
}
impl<'card> BlobHandle {
#[inline(always)]
pub const fn id(&self) -> BlobId {
let Some(ret) = self.id else {
unreachable!();
};
ret
}
#[inline(always)]
pub fn destroy(mut self) -> Result<(), crate::result::Error> {
self.destroy_internal()
}
#[inline]
fn destroy_internal(&mut self) -> Result<(), crate::result::Error> {
if let Some(f) = self.f.upgrade() {
if let Some(blob_id) = self.id.take() {
let mut tmp = crate::ioctl::DrmModeDestroyBlob { blob_id: blob_id.0 };
crate::drm_ioctl(&f, crate::ioctl::DRM_IOCTL_MODE_DESTROYPROPBLOB, &mut tmp)?;
}
}
Ok(())
}
}
impl Drop for BlobHandle {
#[inline(always)]
fn drop(&mut self) {
let _ = self.destroy_internal();
}
}
impl AsRawPropertyValue for BlobHandle {
fn as_raw_property_value(&self) -> u64 {
self.id().0 as u64
}
}
impl IntoRawPropertyValue for BlobHandle {
fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>) {
(self.id().0 as u64, Some(Box::new(self)))
}
}