4
4
//!
5
5
//! C header: [`include/linux/pci.h`](../../../../include/linux/pci.h)
6
6
7
+ #![ allow( dead_code) ]
8
+
7
9
use crate :: {
8
10
bindings, device, driver,
9
11
error:: { from_result, to_result, Result } ,
@@ -28,7 +30,7 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
28
30
pdrv. name = name. as_char_ptr ( ) ;
29
31
pdrv. probe = Some ( Self :: probe_callback) ;
30
32
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 ( ) ;
32
34
to_result ( unsafe { bindings:: __pci_register_driver ( reg, module. 0 , name. as_char_ptr ( ) ) } )
33
35
}
34
36
@@ -40,11 +42,24 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
40
42
impl < T : Driver > Adapter < T > {
41
43
extern "C" fn probe_callback (
42
44
pdev : * mut bindings:: pci_dev ,
43
- _id : * const bindings:: pci_device_id ,
45
+ id : * const bindings:: pci_device_id ,
44
46
) -> core:: ffi:: c_int {
45
47
from_result ( || {
46
48
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) ?;
48
63
unsafe { bindings:: pci_set_drvdata ( pdev, data. into_foreign ( ) as _ ) } ;
49
64
Ok ( 0 )
50
65
} )
@@ -58,6 +73,111 @@ impl<T: Driver> Adapter<T> {
58
73
}
59
74
}
60
75
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
+
61
181
/// A PCI driver
62
182
pub trait Driver {
63
183
/// Data stored on device by driver.
@@ -69,14 +189,17 @@ pub trait Driver {
69
189
/// never move the underlying wrapped data structure. This allows
70
190
type Data : ForeignOwnable + Send + Sync + driver:: DeviceRemoval = ( ) ;
71
191
192
+ /// The type holding information about each device id supported by the driver.
193
+ type IdInfo : ' static = ( ) ;
194
+
72
195
/// 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 > ;
74
197
75
198
/// PCI driver probe.
76
199
///
77
200
/// Called when a new platform device is added or discovered.
78
201
/// 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 > ;
80
203
81
204
/// PCI driver remove.
82
205
///
0 commit comments