rust_drm/
lib.rs

1mod core;
2
3pub mod bus;
4pub mod node;
5
6pub use bus::DrmBus;
7pub use node::{DrmNode, DrmNodeType};
8
9use crate::core::Result;
10use regex::Regex;
11use std::fs::File;
12use std::io::Read;
13
14#[derive(Debug)]
15pub struct PCIBusInfo {
16    domain: u16,
17    bus: u8,
18    dev: u8,
19    func: u8,
20}
21
22impl PCIBusInfo {
23    fn new(pci_slot_name: &str) -> PCIBusInfo {
24        let pci_info_re =
25            Regex::new(r"([0-9a-fA-F]{4}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}).(\d)").unwrap();
26
27        let caps = pci_info_re.captures(pci_slot_name).unwrap();
28        let domain: u16 = u16::from_str_radix(caps.get(1).unwrap().as_str(), 16).unwrap();
29        let bus: u8 = u8::from_str_radix(caps.get(2).unwrap().as_str(), 16).unwrap();
30        let dev: u8 = u8::from_str_radix(caps.get(3).unwrap().as_str(), 16).unwrap();
31        let func: u8 = caps.get(4).unwrap().as_str().parse().unwrap();
32
33        PCIBusInfo {
34            domain,
35            bus,
36            dev,
37            func,
38        }
39    }
40}
41
42#[derive(Debug)]
43pub enum BusInfo {
44    Pci(PCIBusInfo),
45    Usb,
46    Platform,
47    Host1x,
48}
49
50#[derive(Debug)]
51pub struct PCIDeviceInfo {
52    vendor_id: u16,
53    device_id: u16,
54    subvendor_id: u16,
55    subdevice_id: u16,
56    revision_id: u8,
57}
58
59#[derive(Debug)]
60pub enum DeviceInfo {
61    Pci(PCIDeviceInfo),
62    Usb,
63    Platform,
64    Host1x,
65}
66
67#[derive(Debug)]
68pub struct DrmDevice {
69    //    nodes: [&str],
70    available_nodes: i32,
71    bus_type: DrmBus,
72    bus_info: BusInfo,
73}
74
75impl DrmDevice {
76    fn new(node_type: DrmNodeType, subsystem_type: DrmBus, bus_info: BusInfo) -> DrmDevice {
77        DrmDevice {
78            available_nodes: 1 << (node_type as i32),
79            bus_type: subsystem_type,
80            bus_info,
81        }
82    }
83}
84
85pub fn get_uevent_data_by_key(pci_path: std::path::PathBuf, entry_key: &str) -> String {
86    let uevent_path = pci_path.join("uevent");
87    let mut uevent_text: String = String::new();
88    File::open(uevent_path)
89        .unwrap()
90        .read_to_string(&mut uevent_text)
91        .unwrap();
92
93    uevent_text
94        .split("\n")
95        .filter(|entry| entry.starts_with(entry_key))
96        .map(|entry| entry.split("=").last().unwrap())
97        .collect()
98}
99
100pub fn process_device(
101    device_name: &str,
102    expected_subsystem_type: Option<DrmBus>,
103) -> Result<DrmDevice> {
104    let drm_node = DrmNode::from_device_name(device_name)?;
105    if !drm_node.device_dir_exists() {
106        return Err("Device dir for a given DRM Node does not exist")?;
107    }
108
109    let subsystem_type = DrmBus::get_subsystem_type(&drm_node)?;
110    if let Some(expected) = expected_subsystem_type {
111        if expected != subsystem_type {
112            return Err("Expected subsystem type does not match with node")?;
113        }
114    }
115
116    let node_type = DrmNodeType::from_minor_name(device_name)?;
117
118    match node_type {
119        DrmNodeType::Primary => {
120            let pci_path = drm_node.get_device_path();
121            let pci_slot_name = get_uevent_data_by_key(pci_path, "PCI_SLOT_NAME");
122            let bus_info = BusInfo::Pci(PCIBusInfo::new(&pci_slot_name));
123            Ok(DrmDevice::new(node_type, subsystem_type, bus_info))
124        }
125        _ => Err("Unsupported DRM Node Type")?,
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn process_device_happy_path() {
135        process_device("card0", Some(DrmBus::PCI)).unwrap();
136    }
137}