1extern crate alloc;
7
8use alloc::vec::Vec;
9use core::any::Any;
10
11use super::PciAddress;
12use crate::device::{DeviceInfo, DeviceType};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum PciClass {
17 Unclassified = 0x00,
19 MassStorage = 0x01,
21 Network = 0x02,
23 Display = 0x03,
25 Multimedia = 0x04,
27 Memory = 0x05,
29 Bridge = 0x06,
31 Communication = 0x07,
33 SystemPeripheral = 0x08,
35 Input = 0x09,
37 DockingStation = 0x0A,
39 Processor = 0x0B,
41 SerialBus = 0x0C,
43 Wireless = 0x0D,
45 IntelligentIO = 0x0E,
47 Satellite = 0x0F,
49 Encryption = 0x10,
51 SignalProcessing = 0x11,
53 Accelerator = 0x12,
55 Instrumentation = 0x13,
57 Unknown = 0xFF,
59}
60
61impl From<u8> for PciClass {
62 fn from(value: u8) -> Self {
63 match value {
64 0x00 => PciClass::Unclassified,
65 0x01 => PciClass::MassStorage,
66 0x02 => PciClass::Network,
67 0x03 => PciClass::Display,
68 0x04 => PciClass::Multimedia,
69 0x05 => PciClass::Memory,
70 0x06 => PciClass::Bridge,
71 0x07 => PciClass::Communication,
72 0x08 => PciClass::SystemPeripheral,
73 0x09 => PciClass::Input,
74 0x0A => PciClass::DockingStation,
75 0x0B => PciClass::Processor,
76 0x0C => PciClass::SerialBus,
77 0x0D => PciClass::Wireless,
78 0x0E => PciClass::IntelligentIO,
79 0x0F => PciClass::Satellite,
80 0x10 => PciClass::Encryption,
81 0x11 => PciClass::SignalProcessing,
82 0x12 => PciClass::Accelerator,
83 0x13 => PciClass::Instrumentation,
84 _ => PciClass::Unknown,
85 }
86 }
87}
88
89#[derive(Debug, Clone)]
93pub struct PciDeviceInfo {
94 address: PciAddress,
96 vendor_id: u16,
98 device_id: u16,
100 class_code: u32,
102 revision: u8,
104 subsystem_vendor_id: u16,
106 subsystem_id: u16,
108 interrupt_line: u8,
110 interrupt_pin: u8,
112 name: &'static str,
114 id: usize,
116}
117
118impl PciDeviceInfo {
119 #[allow(clippy::too_many_arguments)]
135 pub fn new(
136 address: PciAddress,
137 vendor_id: u16,
138 device_id: u16,
139 class_code: u32,
140 revision: u8,
141 subsystem_vendor_id: u16,
142 subsystem_id: u16,
143 interrupt_line: u8,
144 interrupt_pin: u8,
145 name: &'static str,
146 id: usize,
147 ) -> Self {
148 Self {
149 address,
150 vendor_id,
151 device_id,
152 class_code,
153 revision,
154 subsystem_vendor_id,
155 subsystem_id,
156 interrupt_line,
157 interrupt_pin,
158 name,
159 id,
160 }
161 }
162
163 pub fn address(&self) -> PciAddress {
165 self.address
166 }
167
168 pub fn vendor_id(&self) -> u16 {
170 self.vendor_id
171 }
172
173 pub fn device_id(&self) -> u16 {
175 self.device_id
176 }
177
178 pub fn class_code(&self) -> u32 {
180 self.class_code
181 }
182
183 pub fn base_class(&self) -> u8 {
185 ((self.class_code >> 16) & 0xFF) as u8
186 }
187
188 pub fn subclass(&self) -> u8 {
190 ((self.class_code >> 8) & 0xFF) as u8
191 }
192
193 pub fn interface(&self) -> u8 {
195 (self.class_code & 0xFF) as u8
196 }
197
198 pub fn pci_class(&self) -> PciClass {
200 PciClass::from(self.base_class())
201 }
202
203 pub fn revision(&self) -> u8 {
205 self.revision
206 }
207
208 pub fn subsystem_vendor_id(&self) -> u16 {
210 self.subsystem_vendor_id
211 }
212
213 pub fn subsystem_id(&self) -> u16 {
215 self.subsystem_id
216 }
217
218 pub fn interrupt_line(&self) -> u8 {
220 self.interrupt_line
221 }
222
223 pub fn interrupt_pin(&self) -> u8 {
225 self.interrupt_pin
226 }
227
228 pub fn matches(&self, vendor_id: u16, device_id: u16) -> bool {
230 self.vendor_id == vendor_id && self.device_id == device_id
231 }
232
233 pub fn matches_class(&self, base_class: u8, subclass: Option<u8>) -> bool {
235 if self.base_class() != base_class {
236 return false;
237 }
238 if let Some(sc) = subclass {
239 return self.subclass() == sc;
240 }
241 true
242 }
243
244 pub fn to_device_type(&self) -> DeviceType {
246 match self.pci_class() {
247 PciClass::MassStorage => DeviceType::Block,
248 PciClass::Network => DeviceType::Network,
249 PciClass::Display => DeviceType::Graphics,
250 _ => DeviceType::Generic,
251 }
252 }
253
254 pub fn name(&self) -> &'static str {
256 self.name
257 }
258
259 pub fn id(&self) -> usize {
261 self.id
262 }
263}
264
265impl DeviceInfo for PciDeviceInfo {
266 fn name(&self) -> &'static str {
267 self.name
268 }
269
270 fn id(&self) -> usize {
271 self.id
272 }
273
274 fn compatible(&self) -> Vec<&'static str> {
275 Vec::new()
280 }
281
282 fn as_any(&self) -> &dyn Any {
283 self
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test_case]
292 fn test_pci_device_info_creation() {
293 let addr = PciAddress::new(0, 0, 1, 0);
294 let device = PciDeviceInfo::new(
295 addr,
296 0x8086, 0x1234,
298 0x020000, 0x01,
300 0x0000,
301 0x0000,
302 0x0B,
303 0x01,
304 "pci_device",
305 1,
306 );
307
308 assert_eq!(device.vendor_id(), 0x8086);
309 assert_eq!(device.device_id(), 0x1234);
310 assert_eq!(device.base_class(), 0x02);
311 assert_eq!(device.pci_class(), PciClass::Network);
312 assert_eq!(device.to_device_type(), DeviceType::Network);
313 }
314
315 #[test_case]
316 fn test_pci_device_matching() {
317 let addr = PciAddress::new(0, 0, 1, 0);
318 let device = PciDeviceInfo::new(
319 addr,
320 0x8086,
321 0x1234,
322 0x030000, 0x01,
324 0x0000,
325 0x0000,
326 0x0B,
327 0x01,
328 "pci_device",
329 1,
330 );
331
332 assert!(device.matches(0x8086, 0x1234));
333 assert!(!device.matches(0x8086, 0x5678));
334 assert!(device.matches_class(0x03, None));
335 assert!(device.matches_class(0x03, Some(0x00)));
336 assert!(!device.matches_class(0x02, None));
337 }
338
339 #[test_case]
340 fn test_pci_class_conversion() {
341 assert_eq!(PciClass::from(0x01), PciClass::MassStorage);
342 assert_eq!(PciClass::from(0x02), PciClass::Network);
343 assert_eq!(PciClass::from(0x03), PciClass::Display);
344 assert_eq!(PciClass::from(0xFF), PciClass::Unknown);
345 }
346}