summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--devices/src/pci/mod.rs2
-rw-r--r--devices/src/pci/pci_configuration.rs52
-rw-r--r--devices/src/pci/pci_root.rs1
3 files changed, 53 insertions, 2 deletions
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index a1d211d..ce42d62 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 0030c5e..d5823ac 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 7988a9f..34e4f2a 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,