diff --git a/Cargo.lock b/Cargo.lock index 86d28892a6..971472c4d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,7 +903,7 @@ dependencies = [ [[package]] name = "generic-rt" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#16decee904d8d6d92f27794beab8d3f5b1915358" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#99e8cd93e0d125010130d8e3aee7d343735d8b5c" [[package]] name = "getrandom" @@ -1085,6 +1085,7 @@ dependencies = [ "common", "daemon", "driver-graphics", + "drm-sys", "edid", "embedded-hal", "graphics-ipc", @@ -1777,7 +1778,7 @@ dependencies = [ [[package]] name = "redox-ioctl" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#16decee904d8d6d92f27794beab8d3f5b1915358" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#99e8cd93e0d125010130d8e3aee7d343735d8b5c" dependencies = [ "drm-sys", "redox_syscall 0.6.0", @@ -1804,7 +1805,7 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717" [[package]] name = "redox-rt" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#16decee904d8d6d92f27794beab8d3f5b1915358" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#99e8cd93e0d125010130d8e3aee7d343735d8b5c" dependencies = [ "bitflags 2.10.0", "generic-rt", @@ -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..b77af3e4d9 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,16 @@ 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::{DrmObjectId, DrmObjects, DrmPropertyKind}; pub mod objects; +#[derive(Debug, Copy, Clone)] +pub struct StandardProperties { + pub edid: DrmObjectId, + pub dpms: DrmObjectId, +} + pub trait GraphicsAdapter: Sized + Debug { type Connector: Debug; @@ -32,12 +43,17 @@ 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<()>; - fn probe_connector(&mut self, connector: &mut DrmConnector); + fn probe_connector( + &mut self, + objects: &mut DrmObjects, + standard_properties: &StandardProperties, + id: DrmObjectId, + ); /// The maximum amount of displays that could be attached. /// @@ -78,6 +94,7 @@ pub struct GraphicsScheme { disable_graphical_debug: Option, socket: Socket, objects: DrmObjects, + standard_properties: StandardProperties, next_id: usize, handles: BTreeMap>, @@ -113,8 +130,25 @@ impl GraphicsScheme { ); let mut objects = DrmObjects::new(); - adapter.init(&mut objects); - objects.for_each_connector_mut(|connector| adapter.probe_connector(connector)); + + let edid = objects.add_property("EDID", true, false, DrmPropertyKind::Blob); + 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 { edid, dpms }; + + adapter.init(&mut objects, &standard_properties); + for connector_id in objects.connector_ids().to_vec() { + adapter.probe_connector(&mut objects, &standard_properties, connector_id) + } GraphicsScheme { adapter, @@ -122,6 +156,7 @@ impl GraphicsScheme { disable_graphical_debug, socket, objects, + standard_properties, next_id: 0, handles: BTreeMap::new(), active_vt: 0, @@ -153,6 +188,10 @@ impl GraphicsScheme { (&mut self.adapter, &mut self.objects) } + pub fn standard_properties(&self) -> StandardProperties { + self.standard_properties + } + pub fn handle_vt_event(&mut self, vt_event: VtEvent) { match vt_event.kind { VtEventKind::Activate => { @@ -471,7 +510,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 { @@ -575,20 +614,117 @@ impl SchemeSync for GraphicsScheme { Ok(0) }), ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| { + if data.count_modes() == 0 { + self.adapter.probe_connector( + &mut self.objects, + &self.standard_properties, + DrmObjectId(data.connector_id()), + ); + } let connector = self .objects .get_connector_mut(DrmObjectId(data.connector_id()))?; - if data.count_modes() == 0 { - self.adapter.probe_connector(connector); - } data.set_connection(connector.connection as u32); data.set_modes_ptr(&connector.modes); 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_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { + let blob = self.objects.get_blob(DrmObjectId(data.blob_id()))?; + data.set_data(&blob); Ok(0) }), ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { @@ -665,9 +801,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..3cd6ea3730 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_BLOB, 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,124 @@ 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::Blob(_) => DRM_MODE_OBJECT_BLOB, + 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 uniqueness and value + object.properties.push((property, value)); + } + + pub fn set_object_property(&mut self, object: DrmObjectId, property: DrmObjectId, value: u64) { + let object = self.objects.get_mut(&object).unwrap(); + // FIXME validate property existence and value + for (prop, val) in object.properties.iter_mut() { + if *prop == property { + *val = 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_blob(&mut self, data: Vec) -> DrmObjectId { + let id = self.next_id; + self.objects.insert( + id, + DrmObject { + kind: DrmObjectKind::Blob(data), + properties: vec![], + }, + ); + self.next_id.0 += 1; + + id + } + + pub fn get_blob(&self, id: DrmObjectId) -> Result<&[u8]> { + let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; + match &object.kind { + DrmObjectKind::Blob(data) => Ok(data), + _ => Err(Error::new(EINVAL)), + } + } + 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 +162,7 @@ impl DrmObjects { subpixel: DrmSubpixelOrder::Unknown, driver_data, }), + properties: vec![], }, ); self.connectors.push(connector_id); @@ -52,6 +175,7 @@ impl DrmObjects { possible_crtcs: 0, possible_clones: 0, }), + properties: vec![], }, ); self.encoders.push(encoder_id); @@ -73,15 +197,6 @@ impl DrmObjects { }) } - pub fn for_each_connector_mut<'a>(&mut self, mut f: impl FnMut(&mut DrmConnector)) { - for id in &self.connectors { - match &mut self.objects.get_mut(&id).unwrap().kind { - DrmObjectKind::Connector(connector) => f(connector), - _ => unreachable!(), - } - } - } - pub fn get_connector(&self, id: DrmObjectId) -> Result<&DrmConnector> { let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; match &object.kind { @@ -126,17 +241,44 @@ impl DrmObjectId { pub const INVALID: DrmObjectId = DrmObjectId(0); } +impl From for u64 { + fn from(value: DrmObjectId) -> Self { + value.0.into() + } +} + #[derive(Debug)] struct DrmObject { kind: DrmObjectKind, + properties: Vec<(DrmObjectId, u64)>, } #[derive(Debug)] enum DrmObjectKind { + Property(DrmProperty), + Blob(Vec), 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..8d275c8aeb 100644 --- a/drivers/graphics/ihdgd/src/device/scheme.rs +++ b/drivers/graphics/ihdgd/src/device/scheme.rs @@ -4,10 +4,12 @@ use std::alloc::{self, Layout}; use std::convert::TryInto; use std::ptr::{self, NonNull}; -use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects}; +use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, 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(), + ); } } @@ -60,13 +67,20 @@ impl GraphicsAdapter for Device { } } - fn probe_connector(&mut self, connector: &mut DrmConnector) { + fn probe_connector( + &mut self, + objects: &mut DrmObjects, + _standard_properties: &StandardProperties, + id: DrmObjectId, + ) { + let connector = objects.get_connector_mut(id).unwrap(); let framebuffer = &self.framebuffers[connector.driver_data.framebuffer_id]; connector.connection = DrmConnectorStatus::Connected; connector.modes = vec![modeinfo_for_size( framebuffer.width as u32, framebuffer.height as u32, )]; + // FIXME fetch EDID } fn display_count(&self) -> usize { 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..31d18ba54f 100644 --- a/drivers/graphics/vesad/src/scheme.rs +++ b/drivers/graphics/vesad/src/scheme.rs @@ -2,10 +2,12 @@ use std::alloc::{self, Layout}; use std::convert::TryInto; use std::ptr::{self, NonNull}; -use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects}; +use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, 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(), + ); } } @@ -62,7 +69,13 @@ impl GraphicsAdapter for FbAdapter { } } - fn probe_connector(&mut self, connector: &mut DrmConnector) { + fn probe_connector( + &mut self, + objects: &mut DrmObjects, + _standard_properties: &StandardProperties, + id: DrmObjectId, + ) { + let connector = objects.get_connector_mut(id).unwrap(); connector.modes = vec![modeinfo_for_size( connector.driver_data.width, connector.driver_data.height, 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/main.rs b/drivers/graphics/virtio-gpud/src/main.rs index 16c69d119e..b34af2c60c 100644 --- a/drivers/graphics/virtio-gpud/src/main.rs +++ b/drivers/graphics/virtio-gpud/src/main.rs @@ -32,6 +32,12 @@ use virtio_core::MSIX_PRIMARY_VECTOR; mod scheme; +//const VIRTIO_GPU_F_VIRGL: u32 = 0; +const VIRTIO_GPU_F_EDID: u32 = 1; +//const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2; +//const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3; +//const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4; + const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; const VIRTIO_GPU_MAX_SCANOUTS: usize = 16; @@ -362,6 +368,44 @@ impl XferToHost2d { } } +#[derive(Debug)] +#[repr(C)] +pub struct GetEdid { + pub header: ControlHeader, + pub scanout: u32, + pub padding: u32, +} + +impl GetEdid { + pub fn new(scanout_id: u32) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::GetEdid), + scanout: scanout_id, + padding: 0, + } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct GetEdidResp { + pub header: ControlHeader, + pub size: u32, + pub padding: u32, + pub edid: [u8; 1024], +} + +impl GetEdidResp { + pub fn new() -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::GetEdid), + size: 0, + padding: 0, + edid: [0; 1024], + } + } +} + #[derive(Debug)] #[repr(C)] pub struct CursorPos { @@ -461,6 +505,10 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow: let config = unsafe { &mut *(device.device_space as *mut GpuConfig) }; // Negotiate features. + let has_edid = device.transport.check_device_feature(VIRTIO_GPU_F_EDID); + if has_edid { + device.transport.ack_driver_feature(VIRTIO_GPU_F_EDID); + } device.transport.finalize_features(); // Queue for sending control commands. @@ -483,6 +531,7 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow: control_queue.clone(), cursor_queue.clone(), device.transport.clone(), + has_edid, )?; user_data! { @@ -542,9 +591,12 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow: let events = scheme.adapter().config.events_read.get(); if events & VIRTIO_GPU_EVENT_DISPLAY != 0 { + let standard_properties = scheme.standard_properties(); let (adapter, objects) = scheme.adapter_and_objects_mut(); futures::executor::block_on(async { adapter.update_displays().await.unwrap() }); - objects.for_each_connector_mut(|connector| adapter.probe_connector(connector)); + for connector_id in objects.connector_ids().to_vec() { + adapter.probe_connector(objects, &standard_properties, connector_id); + } scheme.notify_displays_changed(); scheme .adapter_mut() diff --git a/drivers/graphics/virtio-gpud/src/scheme.rs b/drivers/graphics/virtio-gpud/src/scheme.rs index 5d5877a43f..c9efd130b9 100644 --- a/drivers/graphics/virtio-gpud/src/scheme.rs +++ b/drivers/graphics/virtio-gpud/src/scheme.rs @@ -2,10 +2,12 @@ use std::fmt; use std::sync::Arc; use common::{dma::Dma, sgl}; -use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects}; +use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, 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; @@ -74,11 +76,12 @@ pub struct VirtGpuCursor { impl CursorFramebuffer for VirtGpuCursor {} -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub struct Display { enabled: bool, width: u32, height: u32, + edid: Vec, active_resource: Option, } @@ -87,6 +90,7 @@ pub struct VirtGpuAdapter<'a> { control_queue: Arc>, cursor_queue: Arc>, transport: Arc, + has_edid: bool, displays: Vec, } @@ -109,6 +113,7 @@ impl VirtGpuAdapter<'_> { enabled: false, width: 0, height: 0, + edid: vec![], active_resource: None, }, ); @@ -131,6 +136,11 @@ impl VirtGpuAdapter<'_> { self.displays[i].width = info.rect.width; self.displays[i].height = info.rect.height; } + + if self.has_edid { + let edid = self.get_edid(i as u32).await?; + self.displays[i].edid = edid.edid[..edid.size as usize].to_vec(); + } } Ok(()) @@ -174,6 +184,21 @@ impl VirtGpuAdapter<'_> { Ok(response) } + async fn get_edid(&self, scanout_id: u32) -> Result, Error> { + let header = Dma::new(GetEdid::new(scanout_id))?; + + let response = Dma::new(GetEdidResp::new())?; + let command = ChainBuilder::new() + .chain(Buffer::new(&header)) + .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert!(response.header.ty == CommandTy::RespOkEdid); + + Ok(response) + } + fn update_cursor(&mut self, cursor: &VirtGpuCursor, x: i32, y: i32, hot_x: i32, hot_y: i32) { //Transfering cursor resource to host futures::executor::block_on(async { @@ -231,13 +256,21 @@ 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 }); + if self.has_edid { + objects.add_object_property(connector, standard_properties.edid, 0); + } + objects.add_object_property( + connector, + standard_properties.dpms, + DRM_MODE_DPMS_ON.into(), + ); } } @@ -256,8 +289,14 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { } } - fn probe_connector(&mut self, connector: &mut DrmConnector) { + fn probe_connector( + &mut self, + objects: &mut DrmObjects, + standard_properties: &StandardProperties, + id: DrmObjectId, + ) { futures::executor::block_on(async { + let connector = objects.get_connector_mut(id).unwrap(); let display = &self.displays[connector.driver_data.display_id as usize]; connector.modes = vec![modeinfo_for_size(display.width, display.height)]; @@ -266,6 +305,11 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { } else { DrmConnectorStatus::Disconnected }; + + if self.has_edid { + let blob = objects.add_blob(display.edid.clone()); + objects.set_object_property(id, standard_properties.edid, blob.into()); + } }); } @@ -475,12 +519,14 @@ impl<'a> GpuScheme { control_queue: Arc>, cursor_queue: Arc>, transport: Arc, + has_edid: bool, ) -> Result<(GraphicsScheme>, DisplayHandle), Error> { let adapter = VirtGpuAdapter { config, control_queue, cursor_queue, transport, + has_edid, displays: vec![], };