use crate::{PciBusNumber, PciInfoError};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PciLocation {
segment: u16,
bus: u8,
device: u8,
function: u8,
}
impl PciLocation {
pub fn with_bdf(bus: u8, device: u8, function: u8) -> Result<Self, PciInfoError> {
Self::with_segment(0, bus, device, function)
}
pub fn with_bdf_u16(bdf: u16) -> Self {
Self {
segment: 0,
bus: (bdf >> 8) as u8,
device: ((bdf & 0b_1111_1000) >> 3) as u8,
function: (bdf & 0b_111) as u8,
}
}
pub fn with_segment(
segment: u16,
bus: u8,
device: u8,
function: u8,
) -> Result<Self, PciInfoError> {
if device >= 32 || function >= 8 {
Err(PciInfoError::BdfLocationOutOfRange(bus, device, function))
} else {
Ok(Self {
segment,
bus,
device,
function,
})
}
}
pub fn bus(&self) -> u8 {
self.bus
}
pub fn bus_number(&self) -> PciBusNumber {
PciBusNumber::with_segment(self.segment, self.bus)
}
pub fn device(&self) -> u8 {
self.device
}
pub fn function(&self) -> u8 {
self.function
}
pub fn segment(&self) -> u16 {
self.segment
}
}
impl std::fmt::Debug for PciLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{:04X}:{:02X}:{:02X}.{:X}",
self.segment, self.bus, self.device, self.function
)
}
}
impl std::fmt::Display for PciLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{:04X}:{:02X}:{:02X}.{:X}",
self.segment, self.bus, self.device, self.function
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bdf_validation() {
assert!(PciLocation::with_bdf(0, 0, 0).is_ok());
assert!(PciLocation::with_bdf(0, 31, 7).is_ok());
assert!(PciLocation::with_bdf(0, 32, 0).is_err());
assert!(PciLocation::with_bdf(0, 0, 8).is_err());
}
}