44//!
55//! C header: [`include/linux/pci.h`](../../../../include/linux/pci.h)
66
7+ #![ allow( dead_code) ]
8+
79use crate :: {
810 bindings, device, driver,
911 error:: { from_result, to_result, Result } ,
@@ -28,7 +30,7 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
2830 pdrv. name = name. as_char_ptr ( ) ;
2931 pdrv. probe = Some ( Self :: probe_callback) ;
3032 pdrv. remove = Some ( Self :: remove_callback) ;
31- pdrv. id_table = T :: PCI_ID_TABLE . as_ptr ( ) ;
33+ pdrv. id_table = T :: ID_TABLE . as_ref ( ) ;
3234 to_result ( unsafe { bindings:: __pci_register_driver ( reg, module. 0 , name. as_char_ptr ( ) ) } )
3335 }
3436
@@ -40,11 +42,24 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
4042impl < T : Driver > Adapter < T > {
4143 extern "C" fn probe_callback (
4244 pdev : * mut bindings:: pci_dev ,
43- _id : * const bindings:: pci_device_id ,
45+ id : * const bindings:: pci_device_id ,
4446 ) -> core:: ffi:: c_int {
4547 from_result ( || {
4648 let mut dev = unsafe { Device :: from_ptr ( pdev) } ;
47- let data = T :: probe ( & mut dev) ?;
49+
50+ // SAFETY: `id` is a pointer within the static table, so it's always valid.
51+ let offset = unsafe { ( * id) . driver_data } ;
52+ // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
53+ // guarantees that the resulting pointer is within the table.
54+ let info = {
55+ let ptr = unsafe {
56+ id. cast :: < u8 > ( )
57+ . offset ( offset as _ )
58+ . cast :: < Option < T :: IdInfo > > ( )
59+ } ;
60+ unsafe { ( & * ptr) . as_ref ( ) }
61+ } ;
62+ let data = T :: probe ( & mut dev, info) ?;
4863 unsafe { bindings:: pci_set_drvdata ( pdev, data. into_foreign ( ) as _ ) } ;
4964 Ok ( 0 )
5065 } )
@@ -58,6 +73,111 @@ impl<T: Driver> Adapter<T> {
5873 }
5974}
6075
76+ /// Abstraction for bindings::pci_device_id.
77+ #[ derive( Clone , Copy ) ]
78+ pub struct DeviceId {
79+ /// Vendor ID
80+ pub vendor : u32 ,
81+ /// Device ID
82+ pub device : u32 ,
83+ /// Subsystem vendor ID
84+ pub subvendor : u32 ,
85+ /// Subsystem device ID
86+ pub subdevice : u32 ,
87+ /// Device class and subclass
88+ pub class : u32 ,
89+ /// Limit which sub-fields of the class
90+ pub class_mask : u32 ,
91+ }
92+
93+ impl DeviceId {
94+ const PCI_ANY_ID : u32 = !0 ;
95+
96+ /// PCI_DEVICE macro.
97+ pub const fn new ( vendor : u32 , device : u32 ) -> Self {
98+ Self {
99+ vendor,
100+ device,
101+ subvendor : DeviceId :: PCI_ANY_ID ,
102+ subdevice : DeviceId :: PCI_ANY_ID ,
103+ class : 0 ,
104+ class_mask : 0 ,
105+ }
106+ }
107+
108+ /// PCI_DEVICE_CLASS macro.
109+ pub const fn with_class ( class : u32 , class_mask : u32 ) -> Self {
110+ Self {
111+ vendor : DeviceId :: PCI_ANY_ID ,
112+ device : DeviceId :: PCI_ANY_ID ,
113+ subvendor : DeviceId :: PCI_ANY_ID ,
114+ subdevice : DeviceId :: PCI_ANY_ID ,
115+ class,
116+ class_mask,
117+ }
118+ }
119+
120+ pub const fn to_rawid ( & self , offset : isize ) -> bindings:: pci_device_id {
121+ bindings:: pci_device_id {
122+ vendor : self . vendor ,
123+ device : self . device ,
124+ subvendor : self . subvendor ,
125+ subdevice : self . subdevice ,
126+ class : self . class ,
127+ class_mask : self . class_mask ,
128+ driver_data : offset as _ ,
129+ override_only : 0 ,
130+ }
131+ }
132+ }
133+
134+ // SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `pci_device_id::driver_data`.
135+ unsafe impl driver:: RawDeviceId for DeviceId {
136+ type RawType = bindings:: pci_device_id ;
137+
138+ const ZERO : Self :: RawType = bindings:: pci_device_id {
139+ vendor : 0 ,
140+ device : 0 ,
141+ subvendor : 0 ,
142+ subdevice : 0 ,
143+ class : 0 ,
144+ class_mask : 0 ,
145+ driver_data : 0 ,
146+ override_only : 0 ,
147+ } ;
148+
149+ }
150+
151+ /// Define a const pci device id table
152+ ///
153+ /// # Examples
154+ ///
155+ /// ```ignore
156+ /// # use kernel::{pci, define_pci_id_table};
157+ /// #
158+ /// struct MyDriver;
159+ /// impl pci::Driver for MyDriver {
160+ /// // [...]
161+ /// # fn probe(_dev: &mut pci::Device, _id_info: Option<&Self::IdInfo>) -> Result {
162+ /// # Ok(())
163+ /// # }
164+ /// # define_pci_id_table! {u32, [
165+ /// # (pci::DeviceId::new(0x010800, 0xffffff), None),
166+ /// # (pci::DeviceId::with_class(0x010802, 0xfffff), Some(0x10)),
167+ /// # ]}
168+ /// }
169+ /// ```
170+ #[ macro_export]
171+ macro_rules! define_pci_id_table {
172+ ( $data_type: ty, $( $t: tt) * ) => {
173+ type IdInfo = $data_type;
174+ const ID_TABLE : $crate:: driver:: IdTable <' static , $crate:: pci:: DeviceId , $data_type> = {
175+ $crate:: define_id_array!( ARRAY , $crate:: pci:: DeviceId , $data_type, $( $t) * ) ;
176+ ARRAY . as_table( )
177+ } ;
178+ } ;
179+ }
180+
61181/// A PCI driver
62182pub trait Driver {
63183 /// Data stored on device by driver.
@@ -69,14 +189,17 @@ pub trait Driver {
69189 /// never move the underlying wrapped data structure. This allows
70190 type Data : ForeignOwnable + Send + Sync + driver:: DeviceRemoval = ( ) ;
71191
192+ /// The type holding information about each device id supported by the driver.
193+ type IdInfo : ' static = ( ) ;
194+
72195 /// The table of device ids supported by the driver.
73- const PCI_ID_TABLE : & ' static [ bindings :: pci_device_id ] ;
196+ const ID_TABLE : driver :: IdTable < ' static , DeviceId , Self :: IdInfo > ;
74197
75198 /// PCI driver probe.
76199 ///
77200 /// Called when a new platform device is added or discovered.
78201 /// Implementers should attempt to initialize the device here.
79- fn probe ( dev : & mut Device ) -> Result < Self :: Data > ;
202+ fn probe ( dev : & mut Device , id : Option < & Self :: IdInfo > ) -> Result < Self :: Data > ;
80203
81204 /// PCI driver remove.
82205 ///
0 commit comments