diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index a1d211d798..ce42d62514 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -8,7 +8,7 @@ mod pci_configuration; mod pci_device; mod pci_root; -pub use self::pci_configuration::{PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciHeaderType, PciSubclass}; +pub use self::pci_configuration::{PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSubclass}; pub use self::pci_device::Error as PciDeviceError; pub use self::pci_device::PciDevice; pub use self::pci_root::PciRoot; diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs index 0030c5ed58..d5823ac1d1 100644 --- a/devices/src/pci/pci_configuration.rs +++ b/devices/src/pci/pci_configuration.rs @@ -121,6 +121,15 @@ impl PciSubclass for PciSerialBusSubClass { } } +/// A PCI class programming interface. Each combination of `PciClassCode` and +/// `PciSubclass` can specify a set of register-level programming interfaces. +/// This trait is implemented by each programming interface. +/// It allows use of a trait object to generate configurations. +pub trait PciProgrammingInterface { + /// Convert this programming interface to the value used in the PCI specification. + fn get_register_value(&self) -> u8; +} + /// Types of PCI capabilities. pub enum PciCapabilityID { ListID = 0, @@ -169,14 +178,21 @@ impl PciConfiguration { device_id: u16, class_code: PciClassCode, subclass: &PciSubclass, + programming_interface: Option<&PciProgrammingInterface>, header_type: PciHeaderType, subsystem_vendor_id: u16, subsystem_id: u16, ) -> Self { let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS]; registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id); + let pi = if let Some(pi) = programming_interface { + pi.get_register_value() + } else { + 0 + }; registers[2] = u32::from(class_code.get_register_value()) << 24 - | u32::from(subclass.get_register_value()) << 16; + | u32::from(subclass.get_register_value()) << 16 + | u32::from(pi) << 8; match header_type { PciHeaderType::Device => (), PciHeaderType::Bridge => registers[3] = 0x0001_0000, @@ -364,6 +380,7 @@ mod tests { 0x5678, PciClassCode::MultimediaController, &PciMultimediaSubclass::AudioController, + None, PciHeaderType::Device, 0xABCD, 0x2468, @@ -395,4 +412,37 @@ mod tests { assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo } + + #[derive(Copy, Clone)] + enum TestPI { + Test = 0x5a, + } + + impl PciProgrammingInterface for TestPI { + fn get_register_value(&self) -> u8 { + *self as u8 + } + } + + #[test] + fn class_code() { + let cfg = PciConfiguration::new( + 0x1234, + 0x5678, + PciClassCode::MultimediaController, + &PciMultimediaSubclass::AudioController, + Some(&TestPI::Test), + PciHeaderType::Device, + 0xABCD, + 0x2468, + ); + + let class_reg = cfg.read_reg(2); + let class_code = (class_reg >> 24) & 0xFF; + let subclass = (class_reg >> 16) & 0xFF; + let prog_if = (class_reg >> 8) & 0xFF; + assert_eq!(class_code, 0x04); + assert_eq!(subclass, 0x01); + assert_eq!(prog_if, 0x5a); + } } diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs index 7988a9f58f..34e4f2a0d6 100644 --- a/devices/src/pci/pci_root.rs +++ b/devices/src/pci/pci_root.rs @@ -52,6 +52,7 @@ impl PciRoot { 0, PciClassCode::BridgeDevice, &PciBridgeSubclass::HostBridge, + None, PciHeaderType::Bridge, 0, 0,