#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
#[allow(missing_docs)]
pub struct PciBusAddress
{
domain: u16,
bus: BusNumber,
}
impl Into<String> for PciBusAddress
{
#[inline(always)]
fn into(self) -> String
{
(&self).into()
}
}
impl<'a> Into<String> for &'a PciBusAddress
{
#[inline(always)]
fn into(self) -> String
{
format!("{:04x}:{:02x}", self.domain, self.bus)
}
}
impl PciBusAddress
{
#[inline(always)]
pub fn all(sys_path: &SysPath) -> io::Result<HashMap<PciBusAddress, io::Result<PciBusDetails>>>
{
let read_dir = sys_path.class_pci_bus_folder_path().read_dir()?;
let mut pci_buses: HashMap<PciBusAddress, io::Result<PciBusDetails>> = HashMap::new();
for dir_entry in read_dir
{
if let Ok(dir_entry) = dir_entry
{
if let Ok(file_type) = dir_entry.file_type()
{
if !file_type.is_symlink()
{
continue
}
if let Some(pci_bus_address) = Self::parse_pci_bus(&dir_entry)
{
if let Ok(canonical_parent_folder_path_of_pci_bus_folder_path) = dir_entry.path().append(dir_entry.file_name()).append("../..").canonicalize()
{
let details = match pci_bus_address.bus(canonical_parent_folder_path_of_pci_bus_folder_path)
{
Err(error) => Err(error),
Ok(bus) => bus.details()
};
pci_buses.insert(pci_bus_address, details);
}
}
}
}
}
Ok(pci_buses)
}
#[inline(always)]
fn parse_pci_bus(dir_entry: &DirEntry) -> Option<Self>
{
let file_name = dir_entry.file_name();
const Template: &'static [u8] = b"XXXX:YY";
if file_name.len() != Template.len()
{
return None
}
let file_name_bytes = file_name.into_vec();
if unlikely!(file_name_bytes.get_unchecked_value_safe(4) != b':')
{
return None
}
Some
(
Self
{
domain: match u16::parse_hexadecimal_number_upper_or_lower_case(&file_name_bytes[.. 4])
{
Err(_) => return None,
Ok(domain) => domain,
},
bus: match u8::parse_hexadecimal_number_upper_or_lower_case(&file_name_bytes[5 .. 7])
{
Err(_) => return None,
Ok(bus) => bus,
},
}
)
}
pub fn primary(sys_path: &SysPath) -> io::Result<HashSet<PrimaryPciBusAddress>>
{
let read_dir = sys_path.devices_folder_path().read_dir()?;
let mut primary_pci_bus_addresses = HashSet::new();
for dir_entry in read_dir
{
if let Ok(dir_entry) = dir_entry
{
if let Ok(file_type) = dir_entry.file_type()
{
if !file_type.is_dir()
{
continue
}
}
let file_name_bytes = dir_entry.file_name().into_vec();
const Template: &'static [u8] = b"pciXXXX:YY";
if file_name_bytes.len() != Template.len()
{
continue
}
if !file_name_bytes.starts_with(b"pci")
{
continue
}
if unlikely!(file_name_bytes.get_unchecked_value_safe(7) != b':')
{
continue
}
primary_pci_bus_addresses.insert
(
PrimaryPciBusAddress
(
PciBusAddress
{
domain: match u16::parse_hexadecimal_number_upper_or_lower_case(&file_name_bytes[3 .. 7])
{
Err(_) => continue,
Ok(domain) => domain,
},
bus: match u8::parse_hexadecimal_number_upper_or_lower_case(&file_name_bytes[8 .. 10])
{
Err(_) => continue,
Ok(bus) => bus,
},
}
)
);
}
}
Ok(primary_pci_bus_addresses)
}
fn bus(&self, canonical_parent_folder_path_of_pci_bus_folder_path: PathBuf) -> io::Result<PciBus>
{
debug_assert!(canonical_parent_folder_path_of_pci_bus_folder_path.is_absolute(), "Not an absolute path. This isn't a perfect check: whilst a canonical path is always absolute, the reverse is not ncessarily true");
Ok
(
PciBus
{
pci_bus_address: *self,
canonical_parent_folder_path_of_pci_bus_folder_path,
}
)
}
#[inline(always)]
pub fn rescan_all_pci_buses_and_devices(sys_path: &SysPath) -> io::Result<()>
{
sys_path.pci_bus_file_path("rescan").write_value(true)
}
#[inline(always)]
pub fn autoprobe_all_drivers(sys_path: &SysPath) -> io::Result<()>
{
sys_path.pci_bus_file_path("drivers_autoprobe").write_value(true)
}
#[inline(always)]
pub fn probe_all_drivers(sys_path: &SysPath) -> io::Result<()>
{
sys_path.pci_bus_file_path("drivers_probe").write_value(true)
}
pub fn all_resource_alignment(sys_path: &SysPath) -> io::Result<Box<[u8]>>
{
sys_path.pci_bus_file_path("resource_alignment").read_raw()
}
pub fn set_all_resource_alignment<'a>(sys_path: &SysPath, value: impl IntoLineFeedTerminatedByteString<'a>) -> io::Result<()>
{
sys_path.pci_bus_file_path("resource_alignment").write_value(value)
}
pub fn all_slots_folder_path(sys_path: &SysPath) -> PathBuf
{
sys_path.pci_bus_file_path("slots")
}
}