pub mod PCI {
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct BUS_INFO {
pub domain: u16,
pub bus: u8,
pub dev: u8,
pub func: u8,
}
pub enum STATUS {
Current,
Max,
}
#[derive(Debug, Clone)]
pub struct LINK {
pub gen: u8,
pub width: u8,
}
}
#[cfg(feature = "std")]
use std::path::PathBuf;
impl PCI::BUS_INFO {
pub(crate) fn drm_get_device2(
fd: ::core::ffi::c_int,
) -> Result<Self, i32> {
unsafe {
let mut dev_info = __drmGetDevice2(fd, 0)?;
let bus_info = PCI::BUS_INFO {
domain: (*(*dev_info).businfo.pci).domain,
bus: (*(*dev_info).businfo.pci).bus,
dev: (*(*dev_info).businfo.pci).dev,
func: (*(*dev_info).businfo.pci).func,
};
__drmFreeDevice(&mut dev_info);
Ok(bus_info)
}
}
pub fn from_number_str(s: &str) -> Option<Self> {
let mut split = s.split(&[':', '.']).take(4);
let domain = u16::from_str_radix(split.next()?, 16).ok()?;
let [bus, dev, func] = [split.next()?, split.next()?, split.next()?,]
.map(|s| u8::from_str_radix(s, 16).ok());
Some(Self {
domain,
bus: bus?,
dev: dev?,
func: func?,
})
}
#[cfg(feature = "std")]
pub fn get_sysfs_path(&self) -> PathBuf {
PathBuf::from("/sys/bus/pci/devices/").join(self.to_string())
}
#[cfg(feature = "std")]
pub fn get_hwmon_path(&self) -> Option<PathBuf> {
let base = self.get_sysfs_path().join("hwmon");
let Some(hwmon_dir) = std::fs::read_dir(base).ok()
.and_then(|mut read_dir| read_dir.next())
.and_then(|dir| dir.ok()) else { return None };
Some(hwmon_dir.path())
}
#[cfg(feature = "std")]
pub fn get_link_sysfs_path(&self, status: PCI::STATUS) -> [PathBuf; 2] {
let status = match status {
PCI::STATUS::Current => "current",
PCI::STATUS::Max => "max",
};
let path = PathBuf::from(format!("/sys/bus/pci/devices/{}/", self));
[
format!("{status}_link_speed"),
format!("{status}_link_width"),
]
.map(|file_name| path.join(file_name))
}
#[cfg(feature = "std")]
pub fn get_link_info(&self, status: PCI::STATUS) -> PCI::LINK {
let [speed, width] = Self::get_link_sysfs_path(self, status)
.map(|path| std::fs::read_to_string(path).unwrap());
let gen = Self::speed_to_gen(speed.trim());
let width: u8 = width.trim().parse().unwrap();
PCI::LINK {
gen,
width
}
}
#[cfg(feature = "std")]
fn speed_to_gen(speed: &str) -> u8 {
match speed {
"2.5 GT/s PCIe" => 1,
"5.0 GT/s PCIe" => 2,
"8.0 GT/s PCIe" => 3,
"16.0 GT/s PCIe" => 4,
"32.0 GT/s PCIe" => 5,
"64.0 GT/s PCIe" => 6,
_ => 0,
}
}
}
#[cfg(feature = "std")]
use std::fmt;
#[cfg(feature = "std")]
impl fmt::Display for PCI::BUS_INFO {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"{:04x}:{:02x}:{:02x}.{:01x}",
self.domain, self.bus, self.dev, self.func
)
}
}
use crate::bindings;
use crate::{
bindings::{drmDevicePtr, drmFreeDevice},
query_error,
};
use core::mem::MaybeUninit;
unsafe fn __drmGetDevice2(fd: ::core::ffi::c_int, flags: u32) -> Result<drmDevicePtr, i32> {
let mut drm_dev_info: MaybeUninit<drmDevicePtr> = MaybeUninit::uninit();
let r = bindings::drmGetDevice2(fd, flags, drm_dev_info.as_mut_ptr());
let drm_dev_info = drm_dev_info.assume_init();
query_error!(r);
Ok(drm_dev_info)
}
unsafe fn __drmFreeDevice(device: *mut drmDevicePtr) {
drmFreeDevice(device)
}