From f72781f3acb695b4ae574181a4569dc60fa79176 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 1 Apr 2025 14:53:10 -0700 Subject: [PATCH] backend/kms: Use mst `PATH` for output naming --- src/backend/kms/device.rs | 22 ++++++++++++++++++-- src/backend/kms/drm_helpers.rs | 37 +++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 3409a9545..cb46b6dbc 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -44,7 +44,7 @@ use tracing::{error, info, warn}; use std::{ cell::RefCell, collections::{HashMap, HashSet}, - fmt, + fmt::{self, Write}, path::{Path, PathBuf}, sync::{atomic::AtomicBool, mpsc::Receiver, Arc, RwLock}, }; @@ -737,7 +737,25 @@ fn create_output_for_conn(drm: &mut DrmDevice, conn: connector::Handle) -> Resul let conn_info = drm .get_connector(conn, false) .with_context(|| "Failed to query connector info")?; - let interface = drm_helpers::interface_name(drm, conn)?; + let interface = if let Some((parent_interface, ports)) = drm_helpers::mst_path(drm, conn) + .and_then(|(parent_conn, ports)| { + Some((drm_helpers::interface_name(drm, parent_conn).ok()?, ports)) + }) { + // For MST connectors, use parent connector name, hypen, then comma seperated ports + let mut interface = parent_interface; + interface.push('-'); + let mut first = true; + for port in ports { + if !first { + interface.push(','); + } + write!(&mut interface, "{}", port).unwrap(); + first = false; + } + interface + } else { + drm_helpers::interface_name(drm, conn)? + }; let edid_info = drm_helpers::edid_info(drm, conn) .inspect_err(|err| warn!(?err, "failed to get EDID for {}", interface)) .ok(); diff --git a/src/backend/kms/drm_helpers.rs b/src/backend/kms/drm_helpers.rs index 2c4f3d4fc..73f4de510 100644 --- a/src/backend/kms/drm_helpers.rs +++ b/src/backend/kms/drm_helpers.rs @@ -13,7 +13,7 @@ use smithay::{ }, utils::Transform, }; -use std::{collections::HashMap, ops::Range}; +use std::{collections::HashMap, num::NonZeroU32, ops::Range, str::FromStr}; pub fn display_configuration( device: &mut impl ControlDevice, @@ -186,6 +186,41 @@ pub fn edid_info(device: &impl ControlDevice, connector: connector::Handle) -> R edid.ok_or(anyhow!("No EDID found")) } +// For MST connector, return parent connector handle, and ports +// +// https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_connector.c defines +// the format of `PATH`. +pub fn mst_path( + device: &impl ControlDevice, + connector: connector::Handle, +) -> Option<(connector::Handle, Vec)> { + let path_prop = get_prop(device, connector, "PATH").ok()?; + let path_info = device.get_property(path_prop).ok()?; + + let props = device.get_properties(connector).ok()?; + let (ids, vals) = props.as_props_and_values(); + for (&id, &val) in ids.iter().zip(vals.iter()) { + if id == path_prop { + if let property::Value::Blob(edid_blob) = path_info.value_type().convert_value(val) { + let blob = device.get_property_blob(edid_blob).ok()?; + let (parent, ports) = std::str::from_utf8(&blob) + .ok()? + .strip_suffix('\0')? + .strip_prefix("mst:")? + .split_once('-')?; + let parent_connector = connector::Handle::from(parent.parse::().ok()?); + let ports = ports + .split('-') + .map(|i| u32::from_str(i).ok()) + .collect::>>()?; + return Some((parent_connector, ports)); + } + break; + } + } + None +} + pub fn get_prop( device: &impl ControlDevice, handle: impl ResourceHandle,