1use crate::{ConfigRegionAccess, PciAddress};
2use bit_field::BitField;
3use core::fmt::Formatter;
4
5mod msi;
6mod msix;
7
8pub use msi::{MsiCapability, MultipleMessageSupport, TriggerMode};
9pub use msix::MsixCapability;
10
11#[derive(Clone, Copy)]
12pub struct PciCapabilityAddress {
13 pub address: PciAddress,
14 pub offset: u16,
15}
16
17impl core::fmt::Debug for PciCapabilityAddress {
18 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
19 write!(f, "{}, offset: {:02x}", self.address, self.offset)
20 }
21}
22
23#[derive(Clone, Copy, Debug)]
25pub enum PciCapability {
26 PowerManagement(PciCapabilityAddress),
28 AcceleratedGraphicsPort(PciCapabilityAddress),
30 VitalProductData(PciCapabilityAddress),
32 SlotIdentification(PciCapabilityAddress),
34 Msi(MsiCapability),
36 CompactPCIHotswap(PciCapabilityAddress),
38 PciX(PciCapabilityAddress),
40 HyperTransport(PciCapabilityAddress),
42 Vendor(PciCapabilityAddress),
44 DebugPort(PciCapabilityAddress),
46 CompactPCICentralResourceControl(PciCapabilityAddress),
48 PciHotPlugControl(PciCapabilityAddress),
50 BridgeSubsystemVendorId(PciCapabilityAddress),
52 AGP3(PciCapabilityAddress),
54 PciExpress(PciCapabilityAddress),
56 MsiX(MsixCapability),
58 Unknown { address: PciCapabilityAddress, id: u8 },
60}
61
62impl PciCapability {
63 fn parse(
64 id: u8,
65 address: PciCapabilityAddress,
66 extension: u16,
67 access: impl ConfigRegionAccess,
68 ) -> Option<PciCapability> {
69 match id {
70 0x00 => None, 0x01 => Some(PciCapability::PowerManagement(address)),
72 0x02 => Some(PciCapability::AcceleratedGraphicsPort(address)),
73 0x03 => Some(PciCapability::VitalProductData(address)),
74 0x04 => Some(PciCapability::SlotIdentification(address)),
75 0x05 => Some(PciCapability::Msi(MsiCapability::new(address, extension))),
76 0x06 => Some(PciCapability::CompactPCIHotswap(address)),
77 0x07 => Some(PciCapability::PciX(address)),
78 0x08 => Some(PciCapability::HyperTransport(address)),
79 0x09 => Some(PciCapability::Vendor(address)),
80 0x0A => Some(PciCapability::DebugPort(address)),
81 0x0B => Some(PciCapability::CompactPCICentralResourceControl(address)),
82 0x0C => Some(PciCapability::PciHotPlugControl(address)),
83 0x0D => Some(PciCapability::BridgeSubsystemVendorId(address)),
84 0x0E => Some(PciCapability::AGP3(address)),
85 0x10 => Some(PciCapability::PciExpress(address)),
86 0x11 => Some(PciCapability::MsiX(MsixCapability::new(address, extension, access))),
87 _ => Some(PciCapability::Unknown { address, id }),
88 }
89 }
90
91 pub fn address(&self) -> PciCapabilityAddress {
92 match *self {
93 PciCapability::PowerManagement(address) => address,
94 PciCapability::AcceleratedGraphicsPort(address) => address,
95 PciCapability::VitalProductData(address) => address,
96 PciCapability::SlotIdentification(address) => address,
97 PciCapability::Msi(msi_cap) => msi_cap.address,
98 PciCapability::CompactPCIHotswap(address) => address,
99 PciCapability::PciX(address) => address,
100 PciCapability::HyperTransport(address) => address,
101 PciCapability::Vendor(address) => address,
102 PciCapability::DebugPort(address) => address,
103 PciCapability::CompactPCICentralResourceControl(address) => address,
104 PciCapability::PciHotPlugControl(address) => address,
105 PciCapability::BridgeSubsystemVendorId(address) => address,
106 PciCapability::AGP3(address) => address,
107 PciCapability::PciExpress(address) => address,
108 PciCapability::MsiX(msix_cap) => msix_cap.address,
109 PciCapability::Unknown { address, id: _ } => address,
110 }
111 }
112}
113
114pub struct CapabilityIterator<T: ConfigRegionAccess> {
115 address: PciAddress,
116 offset: u16,
117 access: T,
118}
119
120impl<T: ConfigRegionAccess> CapabilityIterator<T> {
121 pub(crate) fn new(address: PciAddress, offset: u16, access: T) -> CapabilityIterator<T> {
122 CapabilityIterator { address, offset, access }
123 }
124}
125
126impl<T: ConfigRegionAccess> Iterator for CapabilityIterator<T> {
127 type Item = PciCapability;
128
129 fn next(&mut self) -> Option<Self::Item> {
130 loop {
131 if self.offset == 0 {
132 return None;
133 }
134 let data = unsafe { self.access.read(self.address, self.offset) };
135 let next_ptr = data.get_bits(8..16);
136 let id = data.get_bits(0..8);
137 let extension = data.get_bits(16..32) as u16;
138 let cap = PciCapability::parse(
139 id as u8,
140 PciCapabilityAddress { address: self.address, offset: self.offset },
141 extension,
142 &self.access,
143 );
144 self.offset = next_ptr as u16;
145 if let Some(cap) = cap {
146 return Some(cap);
147 }
148 }
149 }
150}