From 13f8b090cfd9ebebe06a1d815ba73c924feb1b2c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Dec 2025 20:42:14 +0100 Subject: [PATCH] driver/graphics: Initial support for object properties No support for writing property values or reading blob properties yet. --- Cargo.lock | 3 + drivers/graphics/driver-graphics/src/lib.rs | 146 ++++++++++++++++-- .../graphics/driver-graphics/src/objects.rs | 113 +++++++++++++- drivers/graphics/ihdgd/Cargo.toml | 3 +- drivers/graphics/ihdgd/src/device/scheme.rs | 11 +- drivers/graphics/vesad/Cargo.toml | 1 + drivers/graphics/vesad/src/scheme.rs | 11 +- drivers/graphics/virtio-gpud/Cargo.toml | 1 + drivers/graphics/virtio-gpud/src/scheme.rs | 13 +- 9 files changed, 283 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a020a30ca..971472c4d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1085,6 +1085,7 @@ dependencies = [ "common", "daemon", "driver-graphics", + "drm-sys", "edid", "embedded-hal", "graphics-ipc", @@ -2512,6 +2513,7 @@ dependencies = [ "common", "daemon", "driver-graphics", + "drm-sys", "graphics-ipc", "inputd", "libredox", @@ -2566,6 +2568,7 @@ dependencies = [ "common", "daemon", "driver-graphics", + "drm-sys", "futures", "graphics-ipc", "inputd", diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index a3b34756e5..1c89d48c90 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -9,7 +9,12 @@ use std::mem; use std::mem::transmute; use std::sync::Arc; -use drm_sys::drm_mode_modeinfo; +use drm_sys::{ + drm_mode_modeinfo, drm_mode_property_enum, DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON, + DRM_MODE_DPMS_STANDBY, DRM_MODE_DPMS_SUSPEND, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK, + DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT, + DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, DRM_PROP_NAME_LEN, +}; use graphics_ipc::v1::CursorDamage; use graphics_ipc::v2::Damage; use inputd::{VtEvent, VtEventKind}; @@ -19,10 +24,15 @@ use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket}; use syscall::schemev2::NewFdFlags; use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP}; -use crate::objects::{DrmConnector, DrmObjectId, DrmObjects}; +use crate::objects::{DrmConnector, DrmObjectId, DrmObjects, DrmPropertyKind}; pub mod objects; +#[derive(Debug, Copy, Clone)] +pub struct StandardProperties { + pub dpms: DrmObjectId, +} + pub trait GraphicsAdapter: Sized + Debug { type Connector: Debug; @@ -32,7 +42,7 @@ pub trait GraphicsAdapter: Sized + Debug { fn name(&self) -> &'static [u8]; fn desc(&self) -> &'static [u8]; - fn init(&mut self, objects: &mut DrmObjects); + fn init(&mut self, objects: &mut DrmObjects, standard_properties: &StandardProperties); fn get_cap(&self, cap: u32) -> Result; fn set_client_cap(&self, cap: u32, value: u64) -> Result<()>; @@ -78,6 +88,7 @@ pub struct GraphicsScheme { disable_graphical_debug: Option, socket: Socket, objects: DrmObjects, + standard_properties: StandardProperties, next_id: usize, handles: BTreeMap>, @@ -113,7 +124,21 @@ impl GraphicsScheme { ); let mut objects = DrmObjects::new(); - adapter.init(&mut objects); + + let dpms = objects.add_property( + "DPMS", + false, + false, + DrmPropertyKind::Enum(vec![ + ("On", DRM_MODE_DPMS_ON.into()), + ("Standby", DRM_MODE_DPMS_STANDBY.into()), + ("Suspend", DRM_MODE_DPMS_SUSPEND.into()), + ("Off", DRM_MODE_DPMS_OFF.into()), + ]), + ); + let standard_properties = StandardProperties { dpms }; + + adapter.init(&mut objects, &standard_properties); objects.for_each_connector_mut(|connector| adapter.probe_connector(connector)); GraphicsScheme { @@ -122,6 +147,7 @@ impl GraphicsScheme { disable_graphical_debug, socket, objects, + standard_properties, next_id: 0, handles: BTreeMap::new(), active_vt: 0, @@ -471,7 +497,7 @@ impl SchemeSync for GraphicsScheme { } fn crtc_id(i: u32) -> u32 { - id_index(i) | (1 << 9) + id_index(i) | (1 << 10) } fn fb_id(i: u32) -> u32 { @@ -586,9 +612,97 @@ impl SchemeSync for GraphicsScheme { data.set_mm_width(connector.mm_width); data.set_mm_height(connector.mm_width); data.set_subpixel(connector.subpixel as u32); - data.set_props_ptr(&[]); - data.set_prop_values_ptr(&[]); data.set_encoders_ptr(&[connector.encoder_id.0]); + let props = self + .objects + .get_object_properties(DrmObjectId(data.connector_id()))?; + data.set_props_ptr(&props.iter().map(|&(id, _)| id.0).collect::>()); + data.set_prop_values_ptr( + &props.iter().map(|&(_, value)| value).collect::>(), + ); + Ok(0) + }), + ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { + let property = self.objects.get_property(DrmObjectId(data.prop_id()))?; + data.set_name(property.name); + let mut flags = 0; + if property.immutable { + flags |= DRM_MODE_PROP_IMMUTABLE; + } + if property.atomic { + flags |= DRM_MODE_PROP_ATOMIC; + } + match &property.kind { + &DrmPropertyKind::Range(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_RANGE); + data.set_values_ptr(&[start, end]); + data.set_enum_blob_ptr(&[]); + } + DrmPropertyKind::Enum(variants) => { + data.set_flags(flags | DRM_MODE_PROP_ENUM); + data.set_values_ptr( + &variants.iter().map(|&(_, value)| value).collect::>(), + ); + data.set_enum_blob_ptr( + &variants + .iter() + .map(|&(name, value)| { + let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize]; + for (to, &from) in + name_bytes.iter_mut().zip(name.as_bytes()) + { + *to = from as c_char; + } + drm_mode_property_enum { + name: name_bytes, + value, + } + }) + .collect::>(), + ); + } + DrmPropertyKind::Blob => { + data.set_flags(flags | DRM_MODE_PROP_BLOB); + data.set_values_ptr(&[]); + data.set_enum_blob_ptr(&[]); + } + DrmPropertyKind::Bitmask(bitmask_flags) => { + data.set_flags(flags | DRM_MODE_PROP_BITMASK); + data.set_values_ptr( + &bitmask_flags + .iter() + .map(|&(_, value)| value) + .collect::>(), + ); + data.set_enum_blob_ptr( + &bitmask_flags + .iter() + .map(|&(name, value)| { + let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize]; + for (to, &from) in + name_bytes.iter_mut().zip(name.as_bytes()) + { + *to = from as c_char; + } + drm_mode_property_enum { + name: name_bytes, + value, + } + }) + .collect::>(), + ); + } + DrmPropertyKind::Object => { + data.set_flags(flags | DRM_MODE_PROP_OBJECT); + data.set_values_ptr(&[]); + data.set_enum_blob_ptr(&[]); + } + &DrmPropertyKind::SignedRange(start, end) => { + data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); + data.set_values_ptr(&[start as u64, end as u64]); + data.set_enum_blob_ptr(&[]); + } + } Ok(0) }), ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { @@ -665,9 +779,21 @@ impl SchemeSync for GraphicsScheme { }), ipc::MODE_OBJ_GET_PROPERTIES => { ipc::DrmModeObjGetProperties::with(payload, |mut data| { - // TODO - data.set_props_ptr(&[]); - data.set_prop_values_ptr(&[]); + // FIXME remove once all drm objects are materialized in self.objects + if data.obj_id() >= 1 << 10 { + data.set_props_ptr(&[]); + data.set_prop_values_ptr(&[]); + return Ok(0); + } + + let props = self + .objects + .get_object_properties(DrmObjectId(data.obj_id()))?; + data.set_props_ptr(&props.iter().map(|&(id, _)| id.0).collect::>()); + data.set_prop_values_ptr( + &props.iter().map(|&(_, value)| value).collect::>(), + ); + data.set_obj_type(self.objects.object_type(DrmObjectId(data.obj_id()))?); Ok(0) }) } diff --git a/drivers/graphics/driver-graphics/src/objects.rs b/drivers/graphics/driver-graphics/src/objects.rs index 73e5f93544..cac576231d 100644 --- a/drivers/graphics/driver-graphics/src/objects.rs +++ b/drivers/graphics/driver-graphics/src/objects.rs @@ -1,6 +1,10 @@ use std::collections::HashMap; +use std::ffi::c_char; -use drm_sys::drm_mode_modeinfo; +use drm_sys::{ + drm_mode_modeinfo, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_ENCODER, + DRM_MODE_OBJECT_PROPERTY, DRM_PROP_NAME_LEN, +}; use syscall::{Error, Result, EINVAL}; use crate::GraphicsAdapter; @@ -23,6 +27,91 @@ impl DrmObjects { } } + pub fn object_type(&self, id: DrmObjectId) -> Result { + let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; + Ok(match object.kind { + DrmObjectKind::Property(_) => DRM_MODE_OBJECT_PROPERTY, + DrmObjectKind::Connector(_) => DRM_MODE_OBJECT_CONNECTOR, + DrmObjectKind::Encoder(_) => DRM_MODE_OBJECT_ENCODER, + }) + } + + pub fn add_property( + &mut self, + name: &str, + immutable: bool, + atomic: bool, + kind: DrmPropertyKind, + ) -> DrmObjectId { + if name.len() > DRM_PROP_NAME_LEN as usize { + panic!("Property name {name} is too long"); + } + + match &kind { + DrmPropertyKind::Range(start, end) => assert!(start < end), + DrmPropertyKind::Enum(variants) => { + // FIXME check duplicate variant numbers + for (variant_name, _) in variants { + if variant_name.len() > DRM_PROP_NAME_LEN as usize { + panic!("Property variant name {variant_name} is too long"); + } + } + } + DrmPropertyKind::Blob => {} + DrmPropertyKind::Bitmask(bitmask_flags) => { + // FIXME check overlapping flag numbers + for (flag_name, _) in bitmask_flags { + if flag_name.len() > DRM_PROP_NAME_LEN as usize { + panic!("Property bitflag name {flag_name} is too long"); + } + } + } + DrmPropertyKind::Object => {} + DrmPropertyKind::SignedRange(start, end) => assert!(start < end), + } + + let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize]; + for (to, &from) in name_bytes.iter_mut().zip(name.as_bytes()) { + *to = from as c_char; + } + + let id = self.next_id; + self.objects.insert( + id, + DrmObject { + kind: DrmObjectKind::Property(DrmProperty { + name: name_bytes, + immutable, + atomic, + kind, + }), + properties: vec![], + }, + ); + self.next_id.0 += 1; + + id + } + + pub fn get_property(&self, id: DrmObjectId) -> Result<&DrmProperty> { + let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; + match &object.kind { + DrmObjectKind::Property(drm_property) => Ok(drm_property), + _ => Err(Error::new(EINVAL)), + } + } + + pub fn add_object_property(&mut self, object: DrmObjectId, property: DrmObjectId, value: u64) { + let object = self.objects.get_mut(&object).unwrap(); + // FIXME validate property + object.properties.push((property, value)); + } + + pub fn get_object_properties(&self, id: DrmObjectId) -> Result<&[(DrmObjectId, u64)]> { + let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; + Ok(&object.properties) + } + pub fn add_connector(&mut self, driver_data: T::Connector) -> DrmObjectId { let connector_id = self.next_id; let encoder_id = DrmObjectId(self.next_id.0 + 1); @@ -40,6 +129,7 @@ impl DrmObjects { subpixel: DrmSubpixelOrder::Unknown, driver_data, }), + properties: vec![], }, ); self.connectors.push(connector_id); @@ -52,6 +142,7 @@ impl DrmObjects { possible_crtcs: 0, possible_clones: 0, }), + properties: vec![], }, ); self.encoders.push(encoder_id); @@ -129,14 +220,34 @@ impl DrmObjectId { #[derive(Debug)] struct DrmObject { kind: DrmObjectKind, + properties: Vec<(DrmObjectId, u64)>, } #[derive(Debug)] enum DrmObjectKind { + Property(DrmProperty), Connector(DrmConnector), Encoder(DrmEncoder), } +#[derive(Debug)] +pub struct DrmProperty { + pub name: [c_char; DRM_PROP_NAME_LEN as usize], + pub immutable: bool, + pub atomic: bool, + pub kind: DrmPropertyKind, +} + +#[derive(Debug)] +pub enum DrmPropertyKind { + Range(u64, u64), + Enum(Vec<(&'static str, u64)>), + Blob, + Bitmask(Vec<(&'static str, u64)>), + Object, + SignedRange(i64, i64), +} + #[derive(Debug)] pub struct DrmConnector { pub modes: Vec, diff --git a/drivers/graphics/ihdgd/Cargo.toml b/drivers/graphics/ihdgd/Cargo.toml index 0a04a549d9..f6b6bed1ca 100644 --- a/drivers/graphics/ihdgd/Cargo.toml +++ b/drivers/graphics/ihdgd/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] bitbang-hal = "0.3" +drm-sys = "0.8.0" #TODO: edid is abandoned, fork it an maintain? edid = "0.3.0" #TODO: waiting for bitbang-hal to update to embedded-hal 1.0 @@ -25,4 +26,4 @@ pcid = { path = "../../pcid" } libredox = "0.1.3" redox-scheme = "0.8" redox_event = "0.4.1" -redox_syscall = "0.6" \ No newline at end of file +redox_syscall = "0.6" diff --git a/drivers/graphics/ihdgd/src/device/scheme.rs b/drivers/graphics/ihdgd/src/device/scheme.rs index f6a286f856..68475a0ef8 100644 --- a/drivers/graphics/ihdgd/src/device/scheme.rs +++ b/drivers/graphics/ihdgd/src/device/scheme.rs @@ -7,7 +7,9 @@ use std::ptr::{self, NonNull}; use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects}; use driver_graphics::{ modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, + StandardProperties, }; +use drm_sys::DRM_MODE_DPMS_ON; use graphics_ipc::v1::Damage; use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT}; use syscall::{error::EINVAL, PAGE_SIZE}; @@ -38,10 +40,15 @@ impl GraphicsAdapter for Device { b"Intel HD Graphics" } - fn init(&mut self, objects: &mut DrmObjects) { + fn init(&mut self, objects: &mut DrmObjects, standard_properties: &StandardProperties) { // FIXME enumerate actual connectors for (framebuffer_id, _) in self.framebuffers.iter().enumerate() { - objects.add_connector(Connector { framebuffer_id }); + let connector = objects.add_connector(Connector { framebuffer_id }); + objects.add_object_property( + connector, + standard_properties.dpms, + DRM_MODE_DPMS_ON.into(), + ); } } diff --git a/drivers/graphics/vesad/Cargo.toml b/drivers/graphics/vesad/Cargo.toml index c1cb39e253..474a324c58 100644 --- a/drivers/graphics/vesad/Cargo.toml +++ b/drivers/graphics/vesad/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +drm-sys = "0.8.0" orbclient = "0.3.27" ransid = "0.4" redox_syscall = "0.6" diff --git a/drivers/graphics/vesad/src/scheme.rs b/drivers/graphics/vesad/src/scheme.rs index 69d271047f..fd478a2f45 100644 --- a/drivers/graphics/vesad/src/scheme.rs +++ b/drivers/graphics/vesad/src/scheme.rs @@ -5,7 +5,9 @@ use std::ptr::{self, NonNull}; use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects}; use driver_graphics::{ modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, + StandardProperties, }; +use drm_sys::DRM_MODE_DPMS_ON; use graphics_ipc::v1::Damage; use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT}; use syscall::{EINVAL, PAGE_SIZE}; @@ -39,12 +41,17 @@ impl GraphicsAdapter for FbAdapter { b"VESA" } - fn init(&mut self, objects: &mut DrmObjects) { + fn init(&mut self, objects: &mut DrmObjects, standard_properties: &StandardProperties) { for framebuffer in &self.framebuffers { - objects.add_connector(Connector { + let connector = objects.add_connector(Connector { width: framebuffer.width as u32, height: framebuffer.height as u32, }); + objects.add_object_property( + connector, + standard_properties.dpms, + DRM_MODE_DPMS_ON.into(), + ); } } diff --git a/drivers/graphics/virtio-gpud/Cargo.toml b/drivers/graphics/virtio-gpud/Cargo.toml index 1559cf1f05..50194c890d 100644 --- a/drivers/graphics/virtio-gpud/Cargo.toml +++ b/drivers/graphics/virtio-gpud/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" authors = ["Anhad Singh "] [dependencies] +drm-sys = "0.8.0" log = "0.4" static_assertions = "1.1.0" futures = { version = "0.3.28", features = ["executor"] } diff --git a/drivers/graphics/virtio-gpud/src/scheme.rs b/drivers/graphics/virtio-gpud/src/scheme.rs index 5d5877a43f..1086682877 100644 --- a/drivers/graphics/virtio-gpud/src/scheme.rs +++ b/drivers/graphics/virtio-gpud/src/scheme.rs @@ -4,8 +4,10 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects}; use driver_graphics::{ - modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, GraphicsScheme, + modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, + GraphicsScheme, StandardProperties, }; +use drm_sys::DRM_MODE_DPMS_ON; use graphics_ipc::v1::Damage; use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT}; use inputd::DisplayHandle; @@ -231,13 +233,18 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { b"VirtIO GPU" } - fn init(&mut self, objects: &mut DrmObjects) { + fn init(&mut self, objects: &mut DrmObjects, standard_properties: &StandardProperties) { futures::executor::block_on(async { self.update_displays().await.unwrap(); }); for display_id in 0..self.config.num_scanouts.get() { - objects.add_connector(VirtGpuConnector { display_id }); + let connector = objects.add_connector(VirtGpuConnector { display_id }); + objects.add_object_property( + connector, + standard_properties.dpms, + DRM_MODE_DPMS_ON.into(), + ); } }