1 //! # Property 2 //! 3 //! A property of a modesetting resource. 4 //! 5 //! All modesetting resources have a set of properties that have values that 6 //! can be modified. These properties are modesetting resources themselves, and 7 //! may even have their own set of properties. 8 //! 9 //! Properties may have mutable values attached to them. These can be changed by 10 //! either changing the state of a resource (thereby affecting the property), 11 //! directly changing the property value itself, or by batching property changes 12 //! together and executing them all atomically. 13 14 use crate::control::{RawResourceHandle, ResourceHandle}; 15 use drm_ffi as ffi; 16 17 /// A raw property value that does not have a specific property type 18 pub type RawValue = u64; 19 20 /// A handle to a property 21 #[repr(transparent)] 22 #[derive(Copy, Clone, Hash, PartialEq, Eq)] 23 pub struct Handle(RawResourceHandle); 24 25 // Safety: Handle is repr(transparent) over NonZeroU32 26 unsafe impl bytemuck::ZeroableInOption for Handle {} 27 unsafe impl bytemuck::PodInOption for Handle {} 28 29 impl From<Handle> for RawResourceHandle { from(handle: Handle) -> Self30 fn from(handle: Handle) -> Self { 31 handle.0 32 } 33 } 34 35 impl From<Handle> for u32 { from(handle: Handle) -> Self36 fn from(handle: Handle) -> Self { 37 handle.0.into() 38 } 39 } 40 41 impl From<RawResourceHandle> for Handle { from(handle: RawResourceHandle) -> Self42 fn from(handle: RawResourceHandle) -> Self { 43 Handle(handle) 44 } 45 } 46 47 impl ResourceHandle for Handle { 48 const FFI_TYPE: u32 = ffi::DRM_MODE_OBJECT_PROPERTY; 49 } 50 51 impl std::fmt::Debug for Handle { fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result52 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 53 f.debug_tuple("property::Handle").field(&self.0).finish() 54 } 55 } 56 57 /// Information about a property 58 #[derive(Debug, Clone, Hash, PartialEq, Eq)] 59 pub struct Info { 60 pub(crate) handle: Handle, 61 pub(crate) val_type: ValueType, 62 pub(crate) mutable: bool, 63 pub(crate) atomic: bool, 64 pub(crate) info: ffi::drm_mode_get_property, 65 } 66 67 impl Info { 68 /// Returns the handle to this property. handle(&self) -> Handle69 pub fn handle(&self) -> Handle { 70 self.handle 71 } 72 73 /// Returns the name of this property. name(&self) -> &std::ffi::CStr74 pub fn name(&self) -> &std::ffi::CStr { 75 unsafe { std::ffi::CStr::from_ptr(&self.info.name[0] as _) } 76 } 77 78 /// Returns the ValueType of this property. value_type(&self) -> ValueType79 pub fn value_type(&self) -> ValueType { 80 self.val_type.clone() 81 } 82 83 /// Returns whether this property is mutable. mutable(&self) -> bool84 pub fn mutable(&self) -> bool { 85 self.mutable 86 } 87 88 /// Returns whether this property can be atomically updated. atomic(&self) -> bool89 pub fn atomic(&self) -> bool { 90 self.atomic 91 } 92 } 93 94 /// Describes the types of value that a property uses. 95 #[allow(clippy::upper_case_acronyms)] 96 #[allow(clippy::large_enum_variant)] 97 #[derive(Debug, Clone, Hash, PartialEq, Eq)] 98 pub enum ValueType { 99 /// A catch-all for any unknown types 100 Unknown, 101 /// A True or False type 102 Boolean, 103 /// An unsigned integer that has a min and max value 104 UnsignedRange(u64, u64), 105 /// A signed integer that has a min and max value 106 SignedRange(i64, i64), 107 /// A set of values that are mutually exclusive 108 Enum(EnumValues), 109 /// A set of values that can be combined 110 Bitmask, 111 /// A chunk of binary data that must be acquired 112 Blob, 113 /// A non-specific DRM object 114 Object, 115 /// A CRTC object 116 CRTC, 117 /// A Connector object 118 Connector, 119 /// An Encoder object 120 Encoder, 121 /// A Framebuffer object 122 Framebuffer, 123 /// A Plane object 124 Plane, 125 /// A Property object 126 Property, 127 } 128 129 impl ValueType { 130 /// Given a [`RawValue`], convert it into a specific [`Value`] convert_value(&self, value: RawValue) -> Value131 pub fn convert_value(&self, value: RawValue) -> Value { 132 match self { 133 ValueType::Unknown => Value::Unknown(value), 134 ValueType::Boolean => Value::Boolean(value != 0), 135 ValueType::UnsignedRange(_, _) => Value::UnsignedRange(value), 136 ValueType::SignedRange(_, _) => Value::SignedRange(value as i64), 137 ValueType::Enum(values) => Value::Enum(values.get_value_from_raw_value(value)), 138 ValueType::Bitmask => Value::Bitmask(value), 139 ValueType::Blob => Value::Blob(value), 140 ValueType::Object => Value::Object(bytemuck::cast(value as u32)), 141 ValueType::CRTC => Value::CRTC(bytemuck::cast(value as u32)), 142 ValueType::Connector => Value::Connector(bytemuck::cast(value as u32)), 143 ValueType::Encoder => Value::Encoder(bytemuck::cast(value as u32)), 144 ValueType::Framebuffer => Value::Framebuffer(bytemuck::cast(value as u32)), 145 ValueType::Plane => Value::Plane(bytemuck::cast(value as u32)), 146 ValueType::Property => Value::Property(bytemuck::cast(value as u32)), 147 } 148 } 149 } 150 151 /// The value of a property, in a typed format 152 #[allow(missing_docs)] 153 #[allow(clippy::upper_case_acronyms)] 154 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] 155 pub enum Value<'a> { 156 /// Unknown value 157 Unknown(RawValue), 158 /// Boolean value 159 Boolean(bool), 160 /// Unsigned range value 161 UnsignedRange(u64), 162 /// Signed range value 163 SignedRange(i64), 164 /// Enum Value 165 Enum(Option<&'a EnumValue>), 166 /// Bitmask value 167 Bitmask(u64), 168 /// Opaque (blob) value 169 Blob(u64), 170 /// Unknown object value 171 Object(Option<RawResourceHandle>), 172 /// Crtc object value 173 CRTC(Option<super::crtc::Handle>), 174 /// Connector object value 175 Connector(Option<super::connector::Handle>), 176 /// Encoder object value 177 Encoder(Option<super::encoder::Handle>), 178 /// Framebuffer object value 179 Framebuffer(Option<super::framebuffer::Handle>), 180 /// Plane object value 181 Plane(Option<super::plane::Handle>), 182 /// Property object value 183 Property(Option<Handle>), 184 } 185 186 impl<'a> From<Value<'a>> for RawValue { from(value: Value<'a>) -> Self187 fn from(value: Value<'a>) -> Self { 188 match value { 189 Value::Unknown(x) => x, 190 Value::Boolean(true) => 1, 191 Value::Boolean(false) => 0, 192 Value::UnsignedRange(x) => x, 193 Value::SignedRange(x) => x as u64, 194 Value::Enum(val) => val.map_or(0, EnumValue::value), 195 Value::Bitmask(x) => x, 196 Value::Blob(x) => x, 197 Value::Object(x) => bytemuck::cast::<_, u32>(x) as u64, 198 Value::CRTC(x) => bytemuck::cast::<_, u32>(x) as u64, 199 Value::Connector(x) => bytemuck::cast::<_, u32>(x) as u64, 200 Value::Encoder(x) => bytemuck::cast::<_, u32>(x) as u64, 201 Value::Framebuffer(x) => bytemuck::cast::<_, u32>(x) as u64, 202 Value::Plane(x) => bytemuck::cast::<_, u32>(x) as u64, 203 Value::Property(x) => bytemuck::cast::<_, u32>(x) as u64, 204 } 205 } 206 } 207 208 macro_rules! match_variant { 209 ($this:ident, $variant:ident) => { 210 if let Self::$variant(v) = *$this { 211 Some(v) 212 } else { 213 None 214 } 215 }; 216 } 217 218 impl<'a> Value<'a> { 219 /// Boolean value as_boolean(&self) -> Option<bool>220 pub fn as_boolean(&self) -> Option<bool> { 221 match_variant!(self, Boolean) 222 } 223 224 /// Unsigned range value as_unsigned_range(&self) -> Option<u64>225 pub fn as_unsigned_range(&self) -> Option<u64> { 226 match_variant!(self, UnsignedRange) 227 } 228 229 /// Signed range value as_signed_range(&self) -> Option<i64>230 pub fn as_signed_range(&self) -> Option<i64> { 231 match_variant!(self, SignedRange) 232 } 233 234 /// Enum Value as_enum(&self) -> Option<&'a EnumValue>235 pub fn as_enum(&self) -> Option<&'a EnumValue> { 236 match_variant!(self, Enum).flatten() 237 } 238 239 /// Bitmask value as_bitmask(&self) -> Option<u64>240 pub fn as_bitmask(&self) -> Option<u64> { 241 match_variant!(self, Bitmask) 242 } 243 244 /// Opaque (blob) value as_blob(&self) -> Option<u64>245 pub fn as_blob(&self) -> Option<u64> { 246 match_variant!(self, Blob) 247 } 248 249 /// Unknown object value as_object(&self) -> Option<RawResourceHandle>250 pub fn as_object(&self) -> Option<RawResourceHandle> { 251 match_variant!(self, Object).flatten() 252 } 253 254 /// Crtc object value as_crtc(&self) -> Option<super::crtc::Handle>255 pub fn as_crtc(&self) -> Option<super::crtc::Handle> { 256 match_variant!(self, CRTC).flatten() 257 } 258 259 /// Connector object value as_connector(&self) -> Option<super::connector::Handle>260 pub fn as_connector(&self) -> Option<super::connector::Handle> { 261 match_variant!(self, Connector).flatten() 262 } 263 264 /// Encoder object value as_encoder(&self) -> Option<super::encoder::Handle>265 pub fn as_encoder(&self) -> Option<super::encoder::Handle> { 266 match_variant!(self, Encoder).flatten() 267 } 268 269 /// Framebuffer object value as_framebuffer(&self) -> Option<super::framebuffer::Handle>270 pub fn as_framebuffer(&self) -> Option<super::framebuffer::Handle> { 271 match_variant!(self, Framebuffer).flatten() 272 } 273 274 /// Plane object value as_plane(&self) -> Option<super::plane::Handle>275 pub fn as_plane(&self) -> Option<super::plane::Handle> { 276 match_variant!(self, Plane).flatten() 277 } 278 279 /// Property object value as_property(&self) -> Option<Handle>280 pub fn as_property(&self) -> Option<Handle> { 281 match_variant!(self, Property).flatten() 282 } 283 } 284 285 /// A single value of [`ValueType::Enum`] type 286 #[repr(transparent)] 287 #[derive(Copy, Clone, Hash, PartialEq, Eq, bytemuck::TransparentWrapper)] 288 pub struct EnumValue(ffi::drm_mode_property_enum); 289 290 impl EnumValue { 291 /// Returns the [`RawValue`] of this value value(&self) -> RawValue292 pub fn value(&self) -> RawValue { 293 self.0.value 294 } 295 296 /// Returns the name of this value name(&self) -> &std::ffi::CStr297 pub fn name(&self) -> &std::ffi::CStr { 298 unsafe { std::ffi::CStr::from_ptr(&self.0.name[0] as _) } 299 } 300 } 301 302 impl From<ffi::drm_mode_property_enum> for EnumValue { from(inner: ffi::drm_mode_property_enum) -> Self303 fn from(inner: ffi::drm_mode_property_enum) -> Self { 304 EnumValue(inner) 305 } 306 } 307 308 impl std::fmt::Debug for EnumValue { fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result309 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 310 f.debug_struct("EnumValue") 311 .field("value", &self.value()) 312 .field("name", &self.name()) 313 .finish() 314 } 315 } 316 317 /// A set of [`EnumValue`]s for a single property 318 #[derive(Debug, Clone, Hash, PartialEq, Eq)] 319 pub struct EnumValues { 320 pub(crate) values: Vec<u64>, 321 pub(crate) enums: Vec<EnumValue>, 322 } 323 324 impl EnumValues { 325 /// Returns a tuple containing slices to the [`RawValue`]s and the [`EnumValue`]s values(&self) -> (&[RawValue], &[EnumValue])326 pub fn values(&self) -> (&[RawValue], &[EnumValue]) { 327 (&self.values, &self.enums) 328 } 329 330 /// Returns an [`EnumValue`] for a [`RawValue`], or [`None`] if `value` is 331 /// not part of this [`EnumValues`]. get_value_from_raw_value(&self, value: RawValue) -> Option<&EnumValue>332 pub fn get_value_from_raw_value(&self, value: RawValue) -> Option<&EnumValue> { 333 let (values, enums) = self.values(); 334 let index = if values.get(value as usize) == Some(&value) { 335 // Early-out: indices match values 336 value as usize 337 } else { 338 values.iter().position(|&v| v == value)? 339 }; 340 Some(&enums[index]) 341 } 342 } 343