Skip to main content

libamdgpu_top/
drm_mode.rs

1use std::fmt::Write;
2use std::fs::File;
3use crate::{
4    LibDrm,
5    drmModePropType,
6    drmModeConnectorType,
7    drmModeConnection,
8    drmModeCrtc,
9    drmModeModeInfo,
10    drm_mode_property_enum,
11};
12use crate::DevicePath;
13
14#[derive(Debug, Clone)]
15pub struct ConnectorInfo {
16    pub connector_id: u32,
17    pub connector_type: drmModeConnectorType,
18    pub connector_type_id: u32,
19    pub connection: drmModeConnection,
20    pub mode_info: Vec<drmModeModeInfo>,
21    pub mode_props: Vec<(ModeProp, u64)>,
22    pub crtc: Option<drmModeCrtc>,
23}
24
25impl ConnectorInfo {
26    pub fn name(&self) -> String {
27        format!(
28            "Connector {} ({}-{}), {}",
29            self.connector_id,
30            self.connector_type,
31            self.connector_type_id,
32            self.connection,
33        )
34    }
35}
36
37#[derive(Debug, Clone)]
38pub struct ModeProp {
39    pub prop_type: drmModePropType,
40    pub prop_id: u32,
41    pub flags: u32,
42    pub name: String,
43    pub values: Vec<u64>,
44    pub enums: Vec<drm_mode_property_enum>,
45}
46
47impl ModeProp {
48    pub fn enums_string(&self) -> String {
49        let mut s = self.enums.iter().fold(String::new(), |mut s, enum_| {
50            let _ = write!(s, "{:?}={}, ", enum_.name(), enum_.value);
51            s
52        });
53        let len = s.len();
54        let _ = s.split_off(len-2);
55
56        s
57    }
58}
59
60pub fn connector_info(device_path: &DevicePath) -> Vec<ConnectorInfo> {
61    let Some(libdrm) = device_path.libdrm_amdgpu.clone().map(LibDrm::from) else {
62        return Vec::new();
63    };
64    let fd = {
65        use std::os::fd::IntoRawFd;
66
67        let Some(f) = File::open(&device_path.card).ok() else { return Vec::new() };
68
69        f.into_raw_fd()
70    };
71
72    libdrm.set_all_client_caps(fd);
73    let Some(drm_mode_res) = libdrm.get_drm_mode_resources(fd) else { return Vec::new() };
74    let current_connectors = drm_mode_res.get_drm_mode_all_connector_current(fd);
75
76    let conn_info: Vec<ConnectorInfo> = current_connectors.iter().filter_map(|conn| {
77        let connector_id = conn.connector_id();
78        let connector_type = conn.connector_type();
79        let connector_type_id = conn.connector_type_id();
80        let connection = conn.connection();
81
82        let conn_prop = conn.get_drm_mode_connector_properties(fd)?;
83        let mode_info = conn.get_modes();
84        let mode_props = conn_prop.get_mode_property(fd);
85
86        let mode_props: Vec<(ModeProp, u64)> = mode_props.iter().map(|(prop, value)| {
87            let prop_type = prop.property_type();
88            let flags = prop.flags();
89            let name = prop.name();
90            let prop_id = prop.prop_id();
91            let enums = prop.enums();
92            let values = prop.values();
93
94            let mode_prop = ModeProp {
95                prop_type,
96                prop_id,
97                flags,
98                name,
99                enums,
100                values,
101            };
102
103            (mode_prop, *value)
104        }).collect();
105
106        let crtc_id = mode_props
107            .iter()
108            .find(|prop| prop.0.name == "CRTC_ID")
109            .map(|prop| prop.1);
110
111        let crtc = if let Some(crtc_id) = crtc_id {
112            drm_mode_res
113                .get_drm_mode_all_crtcs(fd)
114                .iter()
115                .copied()
116                .find(|crtc| crtc.crtc_id as u64 == crtc_id)
117        } else {
118            None
119        };
120
121        Some(ConnectorInfo {
122            connector_id,
123            connector_type,
124            connector_type_id,
125            connection,
126            mode_info,
127            mode_props,
128            crtc,
129        })
130    }).collect();
131
132    conn_info
133}