Skip to content

Commit 063fbcd

Browse files
SkallwarCohenArthur
authored andcommitted
rust: add SPI API
This add support for the SPI API for Rust modules. Features: - Register/Unregister - Probe, Remove and Shutdown - write_then_read, write, read 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]> Signed-off-by: Esteban Blanc <[email protected]>
1 parent be91a55 commit 063fbcd

File tree

3 files changed

+309
-1
lines changed

3 files changed

+309
-1
lines changed

rust/kernel/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/of_platform.h>
2020
#include <linux/security.h>
2121
#include <asm/io.h>
22+
#include <linux/spi/spi.h>
2223

2324
// `bindgen` gets confused at certain things
2425
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

rust/kernel/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
coerce_unsized,
2828
dispatch_from_dyn,
2929
unsize,
30-
try_reserve
30+
try_reserve,
31+
bool_to_option
3132
)]
3233

3334
// Ensure conditional compilation based on the kernel configuration works;
@@ -88,6 +89,9 @@ pub use build_error::build_error;
8889
pub use crate::error::{Error, Result};
8990
pub use crate::types::{Mode, ScopeGuard};
9091

92+
#[cfg(CONFIG_SPI)]
93+
pub mod spi;
94+
9195
/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
9296
///
9397
/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h

rust/kernel/spi.rs

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! This module provides safer and higher level abstraction over the kernel's SPI types
4+
//! and functions.
5+
//!
6+
//! C header: [`include/linux/spi/spi.h`](../../../../include/linux/spi/spi.h)
7+
8+
use crate::bindings;
9+
use crate::c_types;
10+
use crate::error::{Error, Result};
11+
use crate::str::CStr;
12+
use alloc::boxed::Box;
13+
use core::pin::Pin;
14+
15+
/// Wrapper struct around the kernel's `spi_device`.
16+
#[derive(Clone, Copy)]
17+
pub struct SpiDevice(*mut bindings::spi_device);
18+
19+
impl SpiDevice {
20+
/// Create an [`SpiDevice`] from a mutable spi_device raw pointer. This function is unsafe
21+
/// as the pointer might be invalid.
22+
///
23+
/// The pointer must be valid. This can be achieved by calling `to_ptr` on a previously
24+
/// constructed, safe `SpiDevice` instance, or by making sure that the pointer points
25+
/// to valid memory.
26+
///
27+
/// You probably do not want to use this abstraction directly. It is mainly used
28+
/// by this abstraction to wrap valid pointers given by the Kernel to the different
29+
/// SPI methods: `probe`, `remove` and `shutdown`.
30+
pub unsafe fn from_ptr(dev: *mut bindings::spi_device) -> Self {
31+
SpiDevice(dev)
32+
}
33+
34+
/// Access the raw pointer from an [`SpiDevice`] instance.
35+
pub fn to_ptr(&mut self) -> *mut bindings::spi_device {
36+
self.0
37+
}
38+
}
39+
40+
/// Registration of an SPI driver.
41+
pub struct DriverRegistration {
42+
this_module: &'static crate::ThisModule,
43+
registered: bool,
44+
name: &'static CStr,
45+
spi_driver: bindings::spi_driver,
46+
}
47+
48+
/// Represents which methods of the SPI driver shall be implemented.
49+
pub struct ToUse {
50+
/// The `probe` field of `spi_driver`.
51+
pub probe: bool,
52+
53+
/// The `remove` field of `spi_driver`.
54+
pub remove: bool,
55+
56+
/// The `shutdown` field of `spi_driver`.
57+
pub shutdown: bool,
58+
}
59+
60+
/// Default table to use for SPI methods. All fields are set to false, meaning that the
61+
/// kernel's default implementations will be used.
62+
pub const USE_NONE: ToUse = ToUse {
63+
probe: false,
64+
remove: false,
65+
shutdown: false,
66+
};
67+
68+
/// Corresponds to the kernel's spi_driver's methods. Implement this trait on a type to
69+
/// express the need of a custom probe, remove or shutdown function for your SPI driver.
70+
/// Use the [`declare_spi_methods`] macro to declare which methods you wish to use.
71+
pub trait SpiMethods {
72+
/// The methods to define. Use [`declare_spi_methods`] to declare them.
73+
const TO_USE: ToUse;
74+
75+
/// Corresponds to the kernel's `spi_driver`'s `probe` method field.
76+
fn probe(mut _spi_dev: SpiDevice) -> Result {
77+
Ok(())
78+
}
79+
80+
/// Corresponds to the kernel's `spi_driver`'s `remove` method field.
81+
fn remove(mut _spi_dev: SpiDevice) -> Result {
82+
Ok(())
83+
}
84+
85+
/// Corresponds to the kernel's `spi_driver`'s `shutdown` method field.
86+
fn shutdown(mut _spi_dev: SpiDevice) {}
87+
}
88+
89+
/// Populate the `TO_USE` field in the [`SpiMethods`] implementer.
90+
///
91+
/// # Examples
92+
///
93+
/// ```
94+
/// impl SpiMethods for MySpiMethods {
95+
/// /// Let's say you only want a probe and remove method, no shutdown.
96+
/// declare_spi_methods!(probe, remove);
97+
///
98+
/// /// Define your probe and remove methods. If you don't, default implementations
99+
/// /// will be used instead. These default implementations do *not* correspond to the
100+
/// /// kernel's default implementations! If you wish to use the kernel's default
101+
/// /// SPI functions implementations, do not declare them using the `declare_spi_methods`
102+
/// /// macro. For example, here our driver will use the kernel's `shutdown` method.
103+
/// fn probe(spi_dev: SpiDevice) -> Result {
104+
/// // ...
105+
///
106+
/// Ok(())
107+
/// }
108+
///
109+
/// fn remove(spi_dev: SpiDevice) -> Result {
110+
/// // ...
111+
///
112+
/// Ok(())
113+
/// }
114+
/// }
115+
/// ```
116+
#[macro_export]
117+
macro_rules! declare_spi_methods {
118+
() => {
119+
const TO_USE: $crate::spi::ToUse = $crate::spi::USE_NONE;
120+
};
121+
($($method:ident),+) => {
122+
const TO_USE: $crate::spi::ToUse = $crate::spi::ToUse {
123+
$($method: true),+,
124+
..$crate::spi::USE_NONE
125+
};
126+
};
127+
}
128+
129+
impl DriverRegistration {
130+
fn new(this_module: &'static crate::ThisModule, name: &'static CStr) -> Self {
131+
DriverRegistration {
132+
this_module,
133+
name,
134+
registered: false,
135+
spi_driver: bindings::spi_driver::default(),
136+
}
137+
}
138+
139+
/// Create a new `DriverRegistration` and register it. This is equivalent to creating
140+
/// a static `spi_driver` and then calling `spi_driver_register` on it in C.
141+
///
142+
/// # Examples
143+
///
144+
/// ```
145+
/// let spi_driver =
146+
/// spi::DriverRegistration::new_pinned::<MySpiMethods>(&THIS_MODULE, cstr!("my_driver_name"))?;
147+
/// ```
148+
pub fn new_pinned<T: SpiMethods>(
149+
this_module: &'static crate::ThisModule,
150+
name: &'static CStr,
151+
) -> Result<Pin<Box<Self>>> {
152+
let mut registration = Pin::from(Box::try_new(Self::new(this_module, name))?);
153+
154+
registration.as_mut().register::<T>()?;
155+
156+
Ok(registration)
157+
}
158+
159+
unsafe extern "C" fn probe_wrapper<T: SpiMethods>(
160+
spi_dev: *mut bindings::spi_device,
161+
) -> c_types::c_int {
162+
// SAFETY: The `spi_dev` pointer is provided by the kernel and is sure to be valid.
163+
match T::probe(unsafe { SpiDevice::from_ptr(spi_dev) }) {
164+
Ok(_) => 0,
165+
Err(e) => e.to_kernel_errno(),
166+
}
167+
}
168+
169+
unsafe extern "C" fn remove_wrapper<T: SpiMethods>(
170+
spi_dev: *mut bindings::spi_device,
171+
) -> c_types::c_int {
172+
// SAFETY: The `spi_dev` pointer is provided by the kernel and is sure to be valid.
173+
match T::remove(unsafe { SpiDevice::from_ptr(spi_dev) }) {
174+
Ok(_) => 0,
175+
Err(e) => e.to_kernel_errno(),
176+
}
177+
}
178+
179+
unsafe extern "C" fn shutdown_wrapper<T: SpiMethods>(spi_dev: *mut bindings::spi_device) {
180+
// SAFETY: The `spi_dev` pointer is provided by the kernel and is sure to be valid.
181+
T::shutdown(unsafe { SpiDevice::from_ptr(spi_dev) })
182+
}
183+
184+
/// Register a [`DriverRegistration`]. This is equivalent to calling `spi_driver_register`
185+
/// on your `spi_driver` in C, without creating it first.
186+
fn register<T: SpiMethods>(self: Pin<&mut Self>) -> Result {
187+
// SAFETY: We do not move out of the reference we get, and are only registering
188+
// `this` once over the course of the module, since we check that the `registered`
189+
// field was not already set to true.
190+
let this = unsafe { self.get_unchecked_mut() };
191+
if this.registered {
192+
return Err(Error::EINVAL);
193+
}
194+
195+
this.spi_driver.driver.name = this.name.as_ptr() as *const c_types::c_char;
196+
this.spi_driver.probe = T::TO_USE
197+
.probe
198+
.then(|| DriverRegistration::probe_wrapper::<T> as _);
199+
this.spi_driver.remove = T::TO_USE
200+
.remove
201+
.then(|| DriverRegistration::remove_wrapper::<T> as _);
202+
this.spi_driver.shutdown = T::TO_USE
203+
.shutdown
204+
.then(|| DriverRegistration::shutdown_wrapper::<T> as _);
205+
206+
// SAFETY: Since we are using a pinned `self`, we can register the driver safely as
207+
// if we were using a static instance. The kernel will access this driver over the
208+
// entire lifespan of a module and therefore needs a pointer valid for the entirety
209+
// of this lifetime.
210+
let res =
211+
unsafe { bindings::__spi_register_driver(this.this_module.0, &mut this.spi_driver) };
212+
213+
if res != 0 {
214+
return Err(Error::from_kernel_errno(res));
215+
}
216+
217+
this.registered = true;
218+
Ok(())
219+
}
220+
}
221+
222+
impl Drop for DriverRegistration {
223+
fn drop(&mut self) {
224+
// SAFETY: We are simply unregistering an `spi_driver` that we know to be valid.
225+
// [`DriverRegistration`] instances can only be created by being registered at the
226+
// same time, so we are sure that we'll never unregister an unregistered `spi_driver`.
227+
unsafe { bindings::driver_unregister(&mut self.spi_driver.driver) }
228+
}
229+
}
230+
231+
// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
232+
// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
233+
unsafe impl Sync for DriverRegistration {}
234+
235+
// SAFETY: All functions work from any thread.
236+
unsafe impl Send for DriverRegistration {}
237+
238+
/// High level abstraction over the kernel's SPI functions such as `spi_write_then_read`.
239+
pub struct Spi;
240+
241+
impl Spi {
242+
/// Corresponds to the kernel's `spi_write_then_read`.
243+
///
244+
/// # Examples
245+
///
246+
/// ```
247+
/// let to_write = "rust-for-linux".as_bytes();
248+
/// let mut to_receive = [0u8; 10]; // let's receive 10 bytes back
249+
///
250+
/// // `spi_device` was previously provided by the kernel in that case
251+
/// let transfer_result = Spi::write_then_read(spi_device, &to_write, &mut to_receive);
252+
/// ```
253+
pub fn write_then_read(dev: &mut SpiDevice, tx_buf: &[u8], rx_buf: &mut [u8]) -> Result {
254+
// SAFETY: The `dev` argument must uphold the safety guarantees made when creating
255+
// the [`SpiDevice`] instance. It should therefore point to a valid `spi_device`
256+
// and valid memory. We also know that a rust slice will always contain a proper
257+
// size and that it is safe to use as is. Converting from a Rust pointer to a
258+
// generic C `void*` pointer is normal, and does not pose size issues on the
259+
// kernel's side, which will use the given Transfer Receive sizes as bytes.
260+
let res = unsafe {
261+
bindings::spi_write_then_read(
262+
dev.to_ptr(),
263+
tx_buf.as_ptr() as *const c_types::c_void,
264+
tx_buf.len() as c_types::c_uint,
265+
rx_buf.as_mut_ptr() as *mut c_types::c_void,
266+
rx_buf.len() as c_types::c_uint,
267+
)
268+
};
269+
270+
match res {
271+
0 => Ok(()), // 0 indicates a valid transfer,
272+
err => Err(Error::from_kernel_errno(err)), // A negative number indicates an error
273+
}
274+
}
275+
276+
/// Corresponds to the kernel's `spi_write`.
277+
///
278+
/// # Examples
279+
///
280+
/// ```
281+
/// let to_write = "rust-for-linux".as_bytes();
282+
///
283+
/// // `spi_device` was previously provided by the kernel in that case
284+
/// let write_result = Spi::write(spi_device, &to_write);
285+
/// ```
286+
pub fn write(dev: &mut SpiDevice, tx_buf: &[u8]) -> Result {
287+
Spi::write_then_read(dev, tx_buf, &mut [0u8; 0])
288+
}
289+
290+
/// Corresponds to the kernel's `spi_read`.
291+
///
292+
/// # Examples
293+
///
294+
/// ```
295+
/// let mut to_receive = [0u8; 10]; // let's receive 10 bytes
296+
///
297+
/// // `spi_device` was previously provided by the kernel in that case
298+
/// let transfer_result = Spi::read(spi_device, &mut to_receive);
299+
/// ```
300+
pub fn read(dev: &mut SpiDevice, rx_buf: &mut [u8]) -> Result {
301+
Spi::write_then_read(dev, &[0u8; 0], rx_buf)
302+
}
303+
}

0 commit comments

Comments
 (0)