polished_pci/
lib.rs

1//! PCI Bus Access and Enumeration Library
2//!
3//! This crate provides basic PCI bus access and enumeration routines for x86 systems.
4//! It is designed for use in `no_std` environments, such as kernels or bootloaders.
5//!
6//! # Features
7//! - Read PCI configuration space
8//! - Enumerate devices on PCI bus 0
9//! - Print device information using a serial logger
10//!
11//! # Example
12//! ```no_run
13//! use polished_pci::pci_enumeration_demo;
14//! pci_enumeration_demo();
15//! ```
16//!
17//! # Integration Examples
18//!
19//! ## Kernel-level Initialization
20//!
21//! ```no_run
22//! // In your kernel's main.rs or init.rs
23//! use polished_pci::pci_enumeration_demo;
24//! // Initialize and enumerate PCI devices (prints to serial logger)
25//! pci_enumeration_demo();
26//! ```
27//!
28//! ## Dumping All PCI Devices
29//!
30//! ```no_run
31//! use polished_pci::scan_bus0_devices;
32//!
33//! // Scan all devices on bus 0
34//! let devices = scan_bus0_devices();
35//! for dev in devices.iter() {
36//!     // Use the fields of dev directly, or print as needed
37//!     // e.g., println!("bus={} device={} vendor={:04x} device={:04x} class={:02x} subclass={:02x}", dev.bus, dev.device, dev.vendor_id, dev.device_id, dev.class, dev.subclass);
38//! }
39//! ```
40//!
41//! ## Finding the First Network Device
42//!
43//! ```no_run
44//! use polished_pci::{scan_bus0_devices, PciDevice, class_code_str};
45//!
46//! // Scan all devices on bus 0
47//! let devices = scan_bus0_devices().unwrap();
48//! // Class code 0x02 is for network controllers
49//! let net_dev = devices.iter().find(|dev| dev.class == 0x02);
50//! if let Some(dev) = net_dev {
51//!     // Do something with the network device
52//!     // e.g., print info or initialize driver
53//! }
54//! ```
55
56#![no_std] // Do not link the Rust standard library. Required for OS/embedded development.
57
58extern crate alloc; // Import the alloc crate for heap-allocated types (e.g., String, Vec)
59
60// --- Module Declarations ---
61// Each module below provides a logical grouping of PCI-related functionality.
62// These are split into separate files for clarity and maintainability.
63
64pub mod bar; // Base Address Register (BAR) handling
65pub mod config; // PCI configuration space access (read/write)
66pub mod device; // PCI device struct and helpers
67pub mod error; // Error types for PCI operations
68pub mod lookup; // Lookup tables for vendor/class names
69pub mod scan; // PCI bus scanning and enumeration routines
70
71mod logger; // Logging interface (e.g., serial output)
72
73// --- Re-exports ---
74// These 'pub use' statements make selected types and functions available at the crate root.
75// This allows users to write `use polished_pci::PciDevice;` instead of `use polished_pci::device::PciDevice;`
76
77pub use bar::{BarInfo, get_bars, probe_bar}; // now return Result types
78pub use config::{
79    pci_config_read, read_config_u8, read_config_u16, read_config_u32, write_config_u8,
80    write_config_u16, write_config_u32,
81};
82pub use device::PciDevice;
83pub use error::PciError;
84pub use lookup::{class_code_str, subclass_str, vendor_id_str};
85pub use scan::{pci_enumeration_demo, print_pci_device, scan_bus0_devices};
86
87// --- Utility Functions ---
88// These are simple helpers for formatting PCI bus/device numbers as strings.
89// They are not part of the public API, but are used internally for display/logging.
90
91use alloc::string::String;
92
93/// Format a PCI bus number as a string for display/logging.
94/// Example: format_bus(2) -> "  bus=2"
95fn format_bus(bus: u8) -> String {
96    use alloc::string::ToString;
97    let mut s = "  bus=".to_string();
98    s.push_str(&bus.to_string());
99    s
100}
101
102/// Format a PCI device number as a string for display/logging.
103/// Example: format_device(5) -> "  device=5"
104fn format_device(device: u8) -> String {
105    use alloc::string::ToString;
106    let mut s = "  device=".to_string();
107    s.push_str(&device.to_string());
108    s
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_pci_device_summary() {
117        let dev = PciDevice {
118            bus: 0,
119            device: 1,
120            function: 0,
121            vendor_id: 0x8086,
122            device_id: 0x1234,
123            class: 0x02,
124            subclass: 0x00,
125            prog_if: 0x00,
126            header_type: 0x00,
127        };
128        let summary = dev.summary();
129        assert!(summary.contains("PCI 00:01.0"));
130        assert!(summary.contains("vendor=8086"));
131        assert!(summary.contains("device=1234"));
132        assert!(summary.contains("class=02"));
133        assert!(summary.contains("subclass=00"));
134    }
135
136    #[test]
137    fn test_vendor_id_str() {
138        assert!(vendor_id_str(0x8086).contains("Intel"));
139        assert!(vendor_id_str(0x10DE).contains("NVIDIA"));
140        assert_eq!(vendor_id_str(0xFFFF), "  vendor=unknown");
141    }
142
143    #[test]
144    fn test_class_code_str() {
145        assert!(class_code_str(0x01).contains("Mass Storage"));
146        assert!(class_code_str(0x02).contains("Network"));
147        assert_eq!(class_code_str(0xFF), "  class=other");
148    }
149
150    #[test]
151    fn test_subclass_str() {
152        assert!(subclass_str(0x80).contains("Other"));
153        assert_eq!(subclass_str(0x05), "  subclass=0x05");
154        assert_eq!(subclass_str(0xFF), "  subclass=other");
155    }
156
157    #[test]
158    fn test_pci_error_eq() {
159        assert_eq!(PciError::DeviceNotFound, PciError::DeviceNotFound);
160        assert_ne!(PciError::DeviceNotFound, PciError::IoFailure);
161    }
162
163    #[test]
164    fn test_format_bus_and_device() {
165        assert_eq!(format_bus(2), "  bus=2");
166        assert_eq!(format_device(5), "  device=5");
167    }
168}