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 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}