driver/graphics: Initial support for object properties

No support for writing property values or reading blob properties yet.
This commit is contained in:
bjorn3
2025-12-21 20:42:14 +01:00
parent 3f982185f2
commit 13f8b090cf
9 changed files with 283 additions and 19 deletions
Generated
+3
View File
@@ -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",
+136 -10
View File
@@ -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<Self>);
fn init(&mut self, objects: &mut DrmObjects<Self>, standard_properties: &StandardProperties);
fn get_cap(&self, cap: u32) -> Result<u64>;
fn set_client_cap(&self, cap: u32, value: u64) -> Result<()>;
@@ -78,6 +88,7 @@ pub struct GraphicsScheme<T: GraphicsAdapter> {
disable_graphical_debug: Option<File>,
socket: Socket,
objects: DrmObjects<T>,
standard_properties: StandardProperties,
next_id: usize,
handles: BTreeMap<usize, Handle<T>>,
@@ -113,7 +124,21 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
);
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<T: GraphicsAdapter> GraphicsScheme<T> {
disable_graphical_debug,
socket,
objects,
standard_properties,
next_id: 0,
handles: BTreeMap::new(),
active_vt: 0,
@@ -471,7 +497,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
}
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<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
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::<Vec<_>>());
data.set_prop_values_ptr(
&props.iter().map(|&(_, value)| value).collect::<Vec<_>>(),
);
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::<Vec<_>>(),
);
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::<Vec<_>>(),
);
}
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::<Vec<_>>(),
);
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::<Vec<_>>(),
);
}
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<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
}),
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::<Vec<_>>());
data.set_prop_values_ptr(
&props.iter().map(|&(_, value)| value).collect::<Vec<_>>(),
);
data.set_obj_type(self.objects.object_type(DrmObjectId(data.obj_id()))?);
Ok(0)
})
}
+112 -1
View File
@@ -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<T: GraphicsAdapter> DrmObjects<T> {
}
}
pub fn object_type(&self, id: DrmObjectId) -> Result<u32> {
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<T: GraphicsAdapter> DrmObjects<T> {
subpixel: DrmSubpixelOrder::Unknown,
driver_data,
}),
properties: vec![],
},
);
self.connectors.push(connector_id);
@@ -52,6 +142,7 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
possible_crtcs: 0,
possible_clones: 0,
}),
properties: vec![],
},
);
self.encoders.push(encoder_id);
@@ -129,14 +220,34 @@ impl DrmObjectId {
#[derive(Debug)]
struct DrmObject<T: GraphicsAdapter> {
kind: DrmObjectKind<T>,
properties: Vec<(DrmObjectId, u64)>,
}
#[derive(Debug)]
enum DrmObjectKind<T: GraphicsAdapter> {
Property(DrmProperty),
Connector(DrmConnector<T>),
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<T: GraphicsAdapter> {
pub modes: Vec<drm_mode_modeinfo>,
+2 -1
View File
@@ -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"
redox_syscall = "0.6"
+9 -2
View File
@@ -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<Self>) {
fn init(&mut self, objects: &mut DrmObjects<Self>, 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(),
);
}
}
+1
View File
@@ -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"
+9 -2
View File
@@ -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<Self>) {
fn init(&mut self, objects: &mut DrmObjects<Self>, 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(),
);
}
}
+1
View File
@@ -5,6 +5,7 @@ edition = "2021"
authors = ["Anhad Singh <andypython@protonmail.com>"]
[dependencies]
drm-sys = "0.8.0"
log = "0.4"
static_assertions = "1.1.0"
futures = { version = "0.3.28", features = ["executor"] }
+10 -3
View File
@@ -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<Self>) {
fn init(&mut self, objects: &mut DrmObjects<Self>, 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(),
);
}
}