#![allow(dead_code)]
use alloc::vec::Vec;
use self::{msix::CapabilityMsixData, vendor::CapabilityVndrData};
use super::{
cfg_space::{PciDeviceCommonCfgOffset, Status},
common_device::PciCommonDevice,
PciDeviceLocation,
};
pub mod msix;
pub mod vendor;
#[derive(Debug)]
pub struct Capability {
id: u8,
pos: u16,
next_ptr: u16,
len: u16,
cap_data: CapabilityData,
}
#[derive(Debug, Clone)]
pub enum CapabilityData {
Pm,
Agp,
Vpd,
SlotId,
Msi,
Chswp,
PciX,
Hp,
Vndr(CapabilityVndrData),
Dbg,
Ccrc,
Shpc,
Ssvid,
Agp3,
Secdev,
Exp,
Msix(CapabilityMsixData),
Sata,
Af,
Ea,
Unknown(u8),
}
impl Capability {
const CAPABILITY_TOP: u16 = 0xFC;
pub fn capability_data(&self) -> &CapabilityData {
&self.cap_data
}
pub(super) fn device_capabilities(dev: &mut PciCommonDevice) -> Vec<Self> {
if !dev.status().contains(Status::CAPABILITIES_LIST) {
return Vec::new();
}
let mut capabilities = Vec::new();
let mut cap_ptr =
dev.location()
.read8(PciDeviceCommonCfgOffset::CapabilitiesPointer as u16) as u16
& PciDeviceLocation::BIT32_ALIGN_MASK;
let mut cap_ptr_vec = Vec::new();
while cap_ptr > 0 {
cap_ptr_vec.push(cap_ptr);
cap_ptr =
dev.location().read8(cap_ptr + 1) as u16 & PciDeviceLocation::BIT32_ALIGN_MASK;
}
cap_ptr_vec.sort();
cap_ptr_vec.push(Self::CAPABILITY_TOP);
let length = cap_ptr_vec.len();
for i in 0..length - 1 {
let cap_ptr = cap_ptr_vec[i];
let next_ptr = cap_ptr_vec[i + 1];
let cap_type = dev.location().read8(cap_ptr);
let data = match cap_type {
0x01 => CapabilityData::Pm,
0x02 => CapabilityData::Agp,
0x03 => CapabilityData::Vpd,
0x04 => CapabilityData::SlotId,
0x05 => CapabilityData::Msi,
0x06 => CapabilityData::Chswp,
0x07 => CapabilityData::PciX,
0x08 => CapabilityData::Hp,
0x09 => {
CapabilityData::Vndr(CapabilityVndrData::new(dev, cap_ptr, next_ptr - cap_ptr))
}
0x0A => CapabilityData::Dbg,
0x0B => CapabilityData::Ccrc,
0x0C => CapabilityData::Shpc,
0x0D => CapabilityData::Ssvid,
0x0E => CapabilityData::Agp3,
0x0F => CapabilityData::Secdev,
0x10 => CapabilityData::Exp,
0x11 => CapabilityData::Msix(CapabilityMsixData::new(dev, cap_ptr)),
0x12 => CapabilityData::Sata,
0x13 => CapabilityData::Af,
0x14 => CapabilityData::Ea,
_ => CapabilityData::Unknown(cap_type),
};
capabilities.push(Self {
id: cap_type,
pos: cap_ptr,
next_ptr,
len: next_ptr - cap_ptr,
cap_data: data,
});
}
capabilities
}
}