1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
// SPDX-License-Identifier: GPL-2.0
//! PCI devices and drivers.
//!
//! C header: [`include/linux/pci.h`](../../../../include/linux/pci.h)
use crate::{
bindings, device, driver,
error::{from_result, to_result, Result},
str::CStr,
types::ForeignOwnable,
ThisModule,
};
/// An adapter for the registration of PCI drivers.
pub struct Adapter<T: Driver>(T);
impl<T: Driver> driver::DriverOps for Adapter<T> {
type RegType = bindings::pci_driver;
unsafe fn register(
reg: *mut bindings::pci_driver,
name: &'static CStr,
module: &'static ThisModule,
) -> Result {
let pdrv: &mut bindings::pci_driver = unsafe { &mut *reg };
pdrv.name = name.as_char_ptr();
pdrv.probe = Some(Self::probe_callback);
pdrv.remove = Some(Self::remove_callback);
pdrv.id_table = T::PCI_ID_TABLE.as_ptr();
to_result(unsafe { bindings::__pci_register_driver(reg, module.0, name.as_char_ptr()) })
}
unsafe fn unregister(reg: *mut bindings::pci_driver) {
unsafe { bindings::pci_unregister_driver(reg) }
}
}
impl<T: Driver> Adapter<T> {
extern "C" fn probe_callback(
pdev: *mut bindings::pci_dev,
_id: *const bindings::pci_device_id,
) -> core::ffi::c_int {
from_result(|| {
let mut dev = unsafe { Device::from_ptr(pdev) };
let data = T::probe(&mut dev)?;
unsafe { bindings::pci_set_drvdata(pdev, data.into_foreign() as _) };
Ok(0)
})
}
extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
let ptr = unsafe { bindings::pci_get_drvdata(pdev) };
let data = unsafe { T::Data::from_foreign(ptr) };
T::remove(&data);
<T::Data as driver::DeviceRemoval>::device_remove(&data);
}
}
/// A PCI driver
pub trait Driver {
/// Data stored on device by driver.
///
/// Corresponds to the data set or retrieved via the kernel's
/// `pci_{set,get}_drvdata()` functions.
///
/// Require that `Data` implements `ForeignOwnable`. We guarantee to
/// never move the underlying wrapped data structure. This allows
type Data: ForeignOwnable + Send + Sync + driver::DeviceRemoval = ();
/// The table of device ids supported by the driver.
const PCI_ID_TABLE: &'static [bindings::pci_device_id];
/// PCI driver probe.
///
/// Called when a new platform device is added or discovered.
/// Implementers should attempt to initialize the device here.
fn probe(dev: &mut Device) -> Result<Self::Data>;
/// PCI driver remove.
///
/// Called when a platform device is removed.
/// Implementers should prepare the device for complete removal here.
fn remove(_data: &Self::Data);
}
/// A PCI device.
///
/// # Invariants
///
/// The field `ptr` is non-null and valid for the lifetime of the object.
pub struct Device {
ptr: *mut bindings::pci_dev,
}
impl Device {
unsafe fn from_ptr(ptr: *mut bindings::pci_dev) -> Self {
Self { ptr }
}
}
unsafe impl device::RawDevice for Device {
fn raw_device(&self) -> *mut bindings::device {
// SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
unsafe { &mut (*self.ptr).dev }
}
}
|