linux_drm/modeset/
props.rs1use alloc::boxed::Box;
2use alloc::sync::Weak;
3use alloc::vec::Vec;
4#[cfg(feature = "stable_polyfill")]
5use ascii::AsAsciiStr;
6
7use crate::ioctl::DrmCardDevice;
8
9use super::{BlobId, PropertyId};
10
11#[derive(Debug)]
12pub struct ModeProp {
13 pub prop_id: PropertyId,
14 pub value: u64,
15}
16
17#[derive(Debug)]
18#[non_exhaustive]
19#[repr(u32)]
20pub enum PropertyType {
21 Unknown = 0,
22 Range = crate::ioctl::DRM_MODE_PROP_RANGE,
23 Enum = crate::ioctl::DRM_MODE_PROP_ENUM,
24 Blob = crate::ioctl::DRM_MODE_PROP_BLOB,
25 Bitmask = crate::ioctl::DRM_MODE_PROP_BITMASK,
26 Object = crate::ioctl::DRM_MODE_PROP_OBJECT,
27 SignedRange = crate::ioctl::DRM_MODE_PROP_SIGNED_RANGE,
28}
29
30impl PropertyType {
31 pub fn from_raw_flags(flags: u32) -> (Self, bool) {
32 let immutable = (flags & crate::ioctl::DRM_MODE_PROP_IMMUTABLE) != 0;
33 let type_raw = flags
34 & (crate::ioctl::DRM_MODE_PROP_LEGACY_TYPE | crate::ioctl::DRM_MODE_PROP_EXTENDED_TYPE);
35 let typ = match type_raw {
36 crate::ioctl::DRM_MODE_PROP_RANGE => Self::Range,
37 crate::ioctl::DRM_MODE_PROP_ENUM => Self::Enum,
38 crate::ioctl::DRM_MODE_PROP_BLOB => Self::Blob,
39 crate::ioctl::DRM_MODE_PROP_BITMASK => Self::Bitmask,
40 crate::ioctl::DRM_MODE_PROP_OBJECT => Self::Object,
41 crate::ioctl::DRM_MODE_PROP_SIGNED_RANGE => Self::SignedRange,
42 _ => Self::Unknown,
43 };
44 (typ, immutable)
45 }
46}
47
48#[derive(Debug)]
49pub struct ObjectPropMeta<'card> {
50 pub(crate) raw: crate::ioctl::DrmModeGetProperty,
51 pub(crate) card: &'card crate::Card,
52}
53
54impl<'card> ObjectPropMeta<'card> {
55 #[inline(always)]
56 pub(crate) fn new(raw: crate::ioctl::DrmModeGetProperty, card: &'card crate::Card) -> Self {
57 Self { raw, card }
58 }
59
60 #[inline]
61 pub fn property_id(&self) -> PropertyId {
62 PropertyId(self.raw.prop_id)
63 }
64
65 pub fn name(&self) -> &str {
66 let raw = &self.raw.name[..];
67 let raw = raw.split(|c| *c == 0).next().unwrap();
68 #[cfg(feature = "stable_polyfill")]
72 return raw.as_ascii_str().expect("non-ascii name?!").as_str();
73
74 #[cfg(not(feature = "stable_polyfill"))]
75 {
76 let raw = unsafe { raw.as_ascii_unchecked() };
77 return raw.as_str();
78 }
79 }
80
81 #[inline]
82 pub fn property_type(&self) -> PropertyType {
83 let (ret, _) = PropertyType::from_raw_flags(self.raw.flags);
84 ret
85 }
86
87 #[inline]
88 pub fn is_immutable(&self) -> bool {
89 let (_, immut) = PropertyType::from_raw_flags(self.raw.flags);
90 immut
91 }
92
93 #[inline]
94 pub fn is_mutable(&self) -> bool {
95 !self.is_immutable()
96 }
97
98 pub fn range(&self) -> Result<(u64, u64), crate::Error> {
105 const RANGE_TYPES: u32 =
106 crate::ioctl::DRM_MODE_PROP_RANGE | crate::ioctl::DRM_MODE_PROP_SIGNED_RANGE;
107 let is_range = (self.raw.flags & RANGE_TYPES) != 0;
108 if !is_range {
109 return Err(crate::Error::NotSupported);
110 }
111 if self.raw.count_values() != 2 {
113 return Err(crate::Error::RemoteFailure);
114 }
115
116 let mut pair = [0_u64; 2];
117
118 let mut tmp = crate::ioctl::DrmModeGetProperty::zeroed();
119 tmp.prop_id = self.raw.prop_id;
120 unsafe { tmp.set_values_ptr(&mut pair as *mut u64, 2) };
121 self.card
122 .ioctl(crate::ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)
123 .unwrap();
124
125 if tmp.count_values() != 2 {
126 return Err(crate::Error::RemoteFailure);
128 }
129
130 Ok((pair[0], pair[1]))
131 }
132
133 pub fn values(&self) -> Result<Vec<u64>, crate::Error> {
147 let mut count = self.raw.count_values() as usize;
148 if count == 0 {
149 return Ok(Vec::new());
150 }
151 loop {
152 let mut values = crate::vec_with_capacity::<u64>(count)?;
153
154 let mut tmp = crate::ioctl::DrmModeGetProperty::zeroed();
155 tmp.prop_id = self.raw.prop_id;
156 unsafe { tmp.set_values_ptr(values.as_mut_ptr(), count as u32) };
157
158 self.card
159 .ioctl(crate::ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)
160 .unwrap();
161
162 let new_count = tmp.count_values() as usize;
163 if new_count != count {
164 count = new_count;
165 continue;
166 }
167
168 unsafe {
171 values.set_len(count);
172 }
173 return Ok(values);
174 }
175 }
176
177 pub fn enum_members(&self) -> Result<Vec<ObjectPropEnumMember>, crate::Error> {
180 const ENUM_TYPES: u32 =
181 crate::ioctl::DRM_MODE_PROP_ENUM | crate::ioctl::DRM_MODE_PROP_BITMASK;
182 let is_enum = (self.raw.flags & ENUM_TYPES) != 0;
183 if !is_enum {
184 return Ok(Vec::new());
185 }
186
187 let mut count = self.raw.count_enum_blobs() as usize;
188 loop {
189 let mut members = crate::vec_with_capacity::<ObjectPropEnumMember>(count)?;
193
194 let mut tmp = crate::ioctl::DrmModeGetProperty::zeroed();
195 tmp.prop_id = self.raw.prop_id;
196 unsafe {
197 tmp.set_enum_blob_ptr(
198 members.as_mut_ptr() as *mut crate::ioctl::DrmModePropertyEnum,
199 count as u32,
200 )
201 };
202
203 self.card
204 .ioctl(crate::ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)
205 .unwrap();
206
207 let new_count = tmp.count_enum_blobs() as usize;
208 if new_count != count {
209 count = new_count;
210 continue;
211 }
212
213 unsafe {
216 members.set_len(count);
217 }
218 return Ok(members);
219 }
220 }
221}
222
223#[derive(Debug)]
224#[repr(transparent)]
225pub struct ObjectPropEnumMember {
226 raw: crate::ioctl::DrmModePropertyEnum,
227}
228
229impl ObjectPropEnumMember {
230 #[inline]
231 pub fn value(&self) -> u64 {
232 self.raw.value
233 }
234
235 pub fn name(&self) -> &str {
236 let raw = &self.raw.name[..];
237 let raw = raw.split(|c| *c == 0).next().unwrap();
238 #[cfg(feature = "stable_polyfill")]
242 return raw.as_ascii_str().expect("non-ascii name?!").as_str();
243
244 #[cfg(not(feature = "stable_polyfill"))]
245 {
246 let raw = raw.as_ascii().unwrap();
247 return raw.as_str();
248 }
249 }
250}
251
252pub trait AsRawPropertyValue {
259 fn as_raw_property_value(&self) -> u64;
260}
261
262pub trait IntoRawPropertyValue: AsRawPropertyValue {
269 fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>);
276}
277
278macro_rules! trivial_as_property_value {
279 ($t:ty) => {
280 impl AsRawPropertyValue for $t {
281 #[inline(always)]
282 fn as_raw_property_value(&self) -> u64 {
283 *self as u64
284 }
285 }
286 impl IntoRawPropertyValue for $t {
287 #[inline(always)]
288 fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>) {
289 (self as u64, None)
290 }
291 }
292 };
293}
294
295trivial_as_property_value!(u64);
296trivial_as_property_value!(u32);
297trivial_as_property_value!(u16);
298trivial_as_property_value!(u8);
299trivial_as_property_value!(usize);
300trivial_as_property_value!(i64);
301trivial_as_property_value!(i32);
302trivial_as_property_value!(i16);
303trivial_as_property_value!(i8);
304trivial_as_property_value!(isize);
305trivial_as_property_value!(bool);
306
307#[derive(Debug)]
311pub struct BlobHandle {
312 pub(crate) id: Option<BlobId>,
313 pub(crate) f: Weak<linux_io::File<DrmCardDevice>>,
314}
315
316impl<'card> BlobHandle {
317 #[inline(always)]
318 pub const fn id(&self) -> BlobId {
319 let Some(ret) = self.id else {
320 unreachable!();
321 };
322 ret
323 }
324
325 #[inline(always)]
327 pub fn destroy(mut self) -> Result<(), crate::result::Error> {
328 self.destroy_internal()
329 }
330
331 #[inline]
332 fn destroy_internal(&mut self) -> Result<(), crate::result::Error> {
333 if let Some(f) = self.f.upgrade() {
334 if let Some(blob_id) = self.id.take() {
335 let mut tmp = crate::ioctl::DrmModeDestroyBlob { blob_id: blob_id.0 };
336 crate::drm_ioctl(&f, crate::ioctl::DRM_IOCTL_MODE_DESTROYPROPBLOB, &mut tmp)?;
337 }
338 }
339 Ok(())
340 }
341}
342
343impl Drop for BlobHandle {
344 #[inline(always)]
345 fn drop(&mut self) {
346 let _ = self.destroy_internal();
347 }
348}
349
350impl AsRawPropertyValue for BlobHandle {
351 fn as_raw_property_value(&self) -> u64 {
352 self.id().0 as u64
353 }
354}
355
356impl IntoRawPropertyValue for BlobHandle {
357 fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>) {
358 (self.id().0 as u64, Some(Box::new(self)))
359 }
360}