Skip to content

Commit b7335b6

Browse files
CohenArthurSkallwar
authored andcommitted
spi: Add VTable for SPI methods
Co-developed-by: Martin Schmidt <[email protected]> Signed-off-by: Martin Schmidt <[email protected]> Co-developed-by: Arthur Cohen <[email protected]> Signed-off-by: Arthur Cohen <[email protected]> spi: Add base for Traits and VTable usage spi: Add "vtable" usage for SPI methods spi: Remove old macro spi: Add documentation for declare_spi_methods, refactor Signed-off-by: Esteban Blanc <[email protected]>
1 parent 1fc9a0d commit b7335b6

File tree

1 file changed

+105
-59
lines changed

1 file changed

+105
-59
lines changed

rust/kernel/spi.rs

Lines changed: 105 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -24,59 +24,135 @@ pub struct DriverRegistration {
2424
this_module: &'static crate::ThisModule,
2525
registered: bool,
2626
name: CStr<'static>,
27-
probe: Option<SpiMethod>,
28-
remove: Option<SpiMethod>,
29-
shutdown: Option<SpiMethodVoid>,
3027
spi_driver: Option<bindings::spi_driver>,
3128
}
3229

30+
pub struct ToUse {
31+
pub probe: bool,
32+
pub remove: bool,
33+
pub shutdown: bool,
34+
}
35+
36+
pub const USE_NONE: ToUse = ToUse {
37+
probe: false,
38+
remove: false,
39+
shutdown: false,
40+
};
41+
42+
pub trait SpiMethods {
43+
const TO_USE: ToUse;
44+
45+
fn probe(_spi_dev: SpiDevice) -> Result {
46+
Ok(())
47+
}
48+
49+
fn remove(_spi_dev: SpiDevice) -> Result {
50+
Ok(())
51+
}
52+
53+
fn shutdown(_spi_dev: SpiDevice) {}
54+
}
55+
56+
/// Populate the TO_USE field in the `SpiMethods` implementer
57+
///
58+
/// ```rust
59+
/// impl SpiMethods for MySpiMethods {
60+
/// /// Let's say you only want a probe and remove method, no shutdown
61+
/// declare_spi_methods!(probe, remove);
62+
///
63+
/// /// Define your probe and remove methods. If you don't, default implementations
64+
/// /// will be used instead. These default implementations do NOT correspond to the
65+
/// /// kernel's default implementations! If you wish to use the Kernel's default
66+
/// /// spi functions implementations, do not declare them using the `declare_spi_methods`
67+
/// /// macro. For example, here our Driver will use the Kernel's shutdown method.
68+
/// fn probe(spi_dev: SpiDevice) -> Result {
69+
/// // ...
70+
///
71+
/// Ok(())
72+
/// }
73+
///
74+
/// fn remove(spi_dev: SpiDevice) -> Result {
75+
/// // ...
76+
///
77+
/// Ok(())
78+
/// }
79+
/// }
80+
/// ```
81+
#[macro_export]
82+
macro_rules! declare_spi_methods {
83+
() => {
84+
const TO_USE: $crate::spi::ToUse = $crate::spi::USE_NONE;
85+
};
86+
($($method:ident),+) => {
87+
const TO_USE: $crate::spi::ToUse = $crate::spi::ToUse {
88+
$($method: true),+,
89+
..$crate::spi::USE_NONE
90+
};
91+
};
92+
}
93+
3394
impl DriverRegistration {
34-
fn new(
35-
this_module: &'static crate::ThisModule,
36-
name: CStr<'static>,
37-
probe: Option<SpiMethod>,
38-
remove: Option<SpiMethod>,
39-
shutdown: Option<SpiMethodVoid>,
40-
) -> Self {
95+
fn new(this_module: &'static crate::ThisModule, name: CStr<'static>) -> Self {
4196
DriverRegistration {
4297
this_module,
4398
name,
4499
registered: false,
45-
probe,
46-
remove,
47-
shutdown,
48100
spi_driver: None,
49101
}
50102
}
51103

52104
// FIXME: Add documentation
53-
pub fn new_pinned(
105+
pub fn new_pinned<T: SpiMethods>(
54106
this_module: &'static crate::ThisModule,
55107
name: CStr<'static>,
56-
probe: Option<SpiMethod>,
57-
remove: Option<SpiMethod>,
58-
shutdown: Option<SpiMethodVoid>,
59108
) -> Result<Pin<Box<Self>>> {
60-
let mut registration = Pin::from(Box::try_new(Self::new(
61-
this_module,
62-
name,
63-
probe,
64-
remove,
65-
shutdown,
66-
))?);
109+
let mut registration = Pin::from(Box::try_new(Self::new(this_module, name))?);
67110

68-
registration.as_mut().register()?;
111+
registration.as_mut().register::<T>()?;
69112

70113
Ok(registration)
71114
}
72115

116+
unsafe extern "C" fn probe_wrapper<T: SpiMethods>(
117+
spi_dev: *mut bindings::spi_device,
118+
) -> c_types::c_int {
119+
// SAFETY: The spi_dev pointer is provided by the kernel and is sure to be valid
120+
match T::probe(SpiDevice::from_ptr(spi_dev)) {
121+
Ok(_) => 0,
122+
Err(e) => e.to_kernel_errno(),
123+
}
124+
}
125+
126+
unsafe extern "C" fn remove_wrapper<T: SpiMethods>(
127+
spi_dev: *mut bindings::spi_device,
128+
) -> c_types::c_int {
129+
// SAFETY: The spi_dev pointer is provided by the kernel and is sure to be valid
130+
match T::remove(SpiDevice::from_ptr(spi_dev)) {
131+
Ok(_) => 0,
132+
Err(e) => e.to_kernel_errno(),
133+
}
134+
}
135+
136+
unsafe extern "C" fn shutdown_wrapper<T: SpiMethods>(spi_dev: *mut bindings::spi_device) {
137+
// SAFETY: The spi_dev pointer is provided by the kernel and is sure to be valid
138+
T::shutdown(SpiDevice::from_ptr(spi_dev))
139+
}
140+
73141
// FIXME: Add documentation
74-
pub fn register(self: Pin<&mut Self>) -> Result {
142+
pub fn register<T: SpiMethods>(self: Pin<&mut Self>) -> Result {
143+
fn maybe_get_wrapper<F>(vtable_value: bool, func: F) -> Option<F> {
144+
match vtable_value {
145+
false => None,
146+
true => Some(func),
147+
}
148+
}
149+
75150
let mut spi_driver = bindings::spi_driver::default();
76151
spi_driver.driver.name = self.name.as_ptr() as *const c_types::c_char;
77-
spi_driver.probe = self.probe;
78-
spi_driver.remove = self.remove;
79-
spi_driver.shutdown = self.shutdown;
152+
153+
spi_driver.probe = maybe_get_wrapper(T::TO_USE.probe, DriverRegistration::probe_wrapper::<T>);
154+
spi_driver.remove = maybe_get_wrapper(T::TO_USE.remove, DriverRegistration::remove_wrapper::<T>);
155+
spi_driver.shutdown = maybe_get_wrapper(T::TO_USE.shutdown, DriverRegistration::shutdown_wrapper::<T>);
80156

81157
let this = unsafe { self.get_unchecked_mut() };
82158
if this.registered {
@@ -115,36 +191,6 @@ unsafe impl Sync for DriverRegistration {}
115191
// SAFETY: All functions work from any thread.
116192
unsafe impl Send for DriverRegistration {}
117193

118-
type SpiMethod = unsafe extern "C" fn(*mut bindings::spi_device) -> c_types::c_int;
119-
type SpiMethodVoid = unsafe extern "C" fn(*mut bindings::spi_device) -> ();
120-
121-
#[macro_export]
122-
macro_rules! spi_method {
123-
(fn $method_name:ident (mut $device_name:ident : SpiDevice) -> Result $block:block) => {
124-
unsafe extern "C" fn $method_name(dev: *mut kernel::bindings::spi_device) -> kernel::c_types::c_int {
125-
use kernel::spi::SpiDevice;
126-
127-
fn inner(mut $device_name: SpiDevice) -> Result $block
128-
129-
// SAFETY: The dev pointer is provided by the kernel and is sure to be valid
130-
match inner(unsafe { SpiDevice::from_ptr(dev) }) {
131-
Ok(_) => 0,
132-
Err(e) => e.to_kernel_errno(),
133-
}
134-
}
135-
};
136-
(fn $method_name:ident (mut $device_name:ident : SpiDevice) $block:block) => {
137-
unsafe extern "C" fn $method_name(dev: *mut kernel::bindings::spi_device) {
138-
use kernel::spi::SpiDevice;
139-
140-
fn inner(mut $device_name: SpiDevice) $block
141-
142-
// SAFETY: The dev pointer is provided by the kernel and is sure to be valid
143-
inner(unsafe { SpiDevice::from_ptr(dev) })
144-
}
145-
};
146-
}
147-
148194
pub struct Spi;
149195

150196
impl Spi {

0 commit comments

Comments
 (0)