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}