Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions src/backend/kms/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -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;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this into another helper function, please?

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();
Expand Down
37 changes: 36 additions & 1 deletion src/backend/kms/drm_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<u32>)> {
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::<NonZeroU32>().ok()?);
let ports = ports
.split('-')
.map(|i| u32::from_str(i).ok())
.collect::<Option<Vec<u32>>>()?;
return Some((parent_connector, ports));
}
break;
}
}
None
}

pub fn get_prop(
device: &impl ControlDevice,
handle: impl ResourceHandle,
Expand Down
Loading