Skip to content

Commit d77db21

Browse files
committed
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 d2e3115 commit d77db21

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/refcount.h>
1212
#include <linux/wait.h>
1313
#include <linux/sched.h>
14+
#include <linux/spi/spi.h>
1415

1516
/* `bindgen` gets confused at certain things. */
1617
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

rust/kernel/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ pub use uapi;
5252
#[doc(hidden)]
5353
pub use build_error::build_error;
5454

55+
#[cfg(CONFIG_SPI)]
56+
pub mod spi;
57+
5558
/// Prefix to appear before log messages printed from within the `kernel` crate.
5659
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
5760

rust/kernel/spi.rs

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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::error::{code::*, from_result, Error, Result};
10+
use crate::str::CStr;
11+
use alloc::boxed::Box;
12+
use core::marker::PhantomData;
13+
use core::pin::Pin;
14+
use macros::vtable;
15+
16+
/// Wrapper struct around the kernel's `spi_device`.
17+
#[derive(Clone, Copy)]
18+
pub struct SpiDevice(*mut bindings::spi_device);
19+
20+
impl SpiDevice {
21+
/// Create an [`SpiDevice`] from a mutable spi_device raw pointer. This function is unsafe
22+
/// as the pointer might be invalid.
23+
///
24+
/// The pointer must be valid. This can be achieved by calling `to_ptr` on a previously
25+
/// constructed, safe `SpiDevice` instance, or by making sure that the pointer points
26+
/// to valid memory.
27+
///
28+
/// You probably do not want to use this abstraction directly. It is mainly used
29+
/// by this abstraction to wrap valid pointers given by the Kernel to the different
30+
/// SPI methods: `probe`, `remove` and `shutdown`.
31+
pub unsafe fn from_ptr(dev: *mut bindings::spi_device) -> Self {
32+
SpiDevice(dev)
33+
}
34+
35+
/// Access the raw pointer from an [`SpiDevice`] instance.
36+
pub fn to_ptr(&mut self) -> *mut bindings::spi_device {
37+
self.0
38+
}
39+
}
40+
41+
/// Corresponds to the kernel's spi_driver's methods. Implement this trait on a type to
42+
/// express the need of a custom probe, remove or shutdown function for your SPI driver.
43+
#[vtable]
44+
pub trait SpiMethods {
45+
/// Corresponds to the kernel's `spi_driver`'s `probe` method field.
46+
fn probe(_spi_dev: &mut SpiDevice) -> Result<i32> {
47+
unreachable!("There should be a NULL in the probe filed of spi_driver's");
48+
}
49+
50+
/// Corresponds to the kernel's `spi_driver`'s `remove` method field.
51+
fn remove(_spi_dev: &mut SpiDevice) {
52+
unreachable!("There should be a NULL in the remove filed of spi_driver's");
53+
}
54+
55+
/// Corresponds to the kernel's `spi_driver`'s `shutdown` method field.
56+
fn shutdown(_spi_dev: &mut SpiDevice) {
57+
unreachable!("There should be a NULL in the shutdown filed of spi_driver's");
58+
}
59+
}
60+
61+
/// Registration of an SPI driver.
62+
pub struct DriverRegistration<T: SpiMethods> {
63+
this_module: &'static crate::ThisModule,
64+
registered: bool,
65+
name: &'static CStr,
66+
spi_driver: bindings::spi_driver,
67+
_p: PhantomData<T>,
68+
}
69+
70+
impl<T: SpiMethods> DriverRegistration<T> {
71+
fn new(this_module: &'static crate::ThisModule, name: &'static CStr) -> Self {
72+
DriverRegistration {
73+
this_module,
74+
name,
75+
registered: false,
76+
spi_driver: bindings::spi_driver::default(),
77+
_p: PhantomData,
78+
}
79+
}
80+
81+
/// Create a new `DriverRegistration` and register it. This is equivalent to creating
82+
/// a static `spi_driver` and then calling `spi_driver_register` on it in C.
83+
///
84+
/// # Examples
85+
///
86+
/// ```
87+
/// let spi_driver =
88+
/// spi::DriverRegistration::new_pinned::<MySpiMethods>(&THIS_MODULE, cstr!("my_driver_name"))?;
89+
/// ```
90+
pub fn new_pinned(
91+
this_module: &'static crate::ThisModule,
92+
name: &'static CStr,
93+
) -> Result<Pin<Box<Self>>> {
94+
let mut registration = Pin::from(Box::try_new(Self::new(this_module, name))?);
95+
96+
registration.as_mut().register()?;
97+
98+
Ok(registration)
99+
}
100+
101+
/// Register a [`DriverRegistration`]. This is equivalent to calling `spi_driver_register`
102+
/// on your `spi_driver` in C, without creating it first.
103+
fn register(self: Pin<&mut Self>) -> Result {
104+
// SAFETY: We do not move out of the reference we get, and are only registering
105+
// `this` once over the course of the module, since we check that the `registered`
106+
// field was not already set to true.
107+
let this = unsafe { self.get_unchecked_mut() };
108+
if this.registered {
109+
return Err(EINVAL);
110+
}
111+
112+
let mut spi_driver = this.spi_driver;
113+
114+
if T::HAS_PROBE {
115+
spi_driver.probe = Some(probe_callback::<T>);
116+
}
117+
if T::HAS_REMOVE {
118+
spi_driver.remove = Some(remove_callback::<T>);
119+
}
120+
if T::HAS_SHUTDOWN {
121+
spi_driver.remove = Some(shutdown_callback::<T>);
122+
}
123+
124+
spi_driver.driver.name = this.name.as_ptr() as *const core::ffi::c_char;
125+
126+
// SAFETY: Since we are using a pinned `self`, we can register the driver safely as
127+
// if we were using a static instance. The kernel will access this driver over the
128+
// entire lifespan of a module and therefore needs a pointer valid for the entirety
129+
// of this lifetime.
130+
let res =
131+
unsafe { bindings::__spi_register_driver(this.this_module.0, &mut this.spi_driver) };
132+
133+
if res != 0 {
134+
return Err(Error::from_errno(res));
135+
}
136+
137+
this.registered = true;
138+
139+
Ok(())
140+
}
141+
}
142+
143+
impl<T: SpiMethods> Drop for DriverRegistration<T> {
144+
fn drop(&mut self) {
145+
// SAFETY: We are simply unregistering an `spi_driver` that we know to be valid.
146+
// [`DriverRegistration`] instances can only be created by being registered at the
147+
// same time, so we are sure that we'll never unregister an unregistered `spi_driver`.
148+
unsafe { bindings::driver_unregister(&mut self.spi_driver.driver) }
149+
}
150+
}
151+
152+
unsafe extern "C" fn probe_callback<T: SpiMethods>(
153+
spi: *mut bindings::spi_device,
154+
) -> core::ffi::c_int {
155+
from_result(|| Ok(T::probe(&mut SpiDevice(spi))?))
156+
}
157+
158+
unsafe extern "C" fn remove_callback<T: SpiMethods>(spi: *mut bindings::spi_device) {
159+
T::remove(&mut SpiDevice(spi));
160+
}
161+
162+
unsafe extern "C" fn shutdown_callback<T: SpiMethods>(spi: *mut bindings::spi_device) {
163+
T::shutdown(&mut SpiDevice(spi));
164+
}
165+
166+
// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
167+
// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
168+
unsafe impl<T: SpiMethods> Sync for DriverRegistration<T> {}
169+
170+
// SAFETY: All functions work from any thread.
171+
unsafe impl<T: SpiMethods> Send for DriverRegistration<T> {}
172+
173+
/// High level abstraction over the kernel's SPI functions such as `spi_write_then_read`.
174+
// TODO this should be a mod, right?
175+
pub struct Spi;
176+
177+
impl Spi {
178+
/// Corresponds to the kernel's `spi_write_then_read`.
179+
///
180+
/// # Examples
181+
///
182+
/// ```
183+
/// let to_write = "rust-for-linux".as_bytes();
184+
/// let mut to_receive = [0u8; 10]; // let's receive 10 bytes back
185+
///
186+
/// // `spi_device` was previously provided by the kernel in that case
187+
/// let transfer_result = Spi::write_then_read(spi_device, &to_write, &mut to_receive);
188+
/// ```
189+
pub fn write_then_read(dev: &mut SpiDevice, tx_buf: &[u8], rx_buf: &mut [u8]) -> Result {
190+
// SAFETY: The `dev` argument must uphold the safety guarantees made when creating
191+
// the [`SpiDevice`] instance. It should therefore point to a valid `spi_device`
192+
// and valid memory. We also know that a rust slice will always contain a proper
193+
// size and that it is safe to use as is. Converting from a Rust pointer to a
194+
// generic C `void*` pointer is normal, and does not pose size issues on the
195+
// kernel's side, which will use the given Transfer Receive sizes as bytes.
196+
let res = unsafe {
197+
bindings::spi_write_then_read(
198+
dev.to_ptr(),
199+
tx_buf.as_ptr() as *const core::ffi::c_void,
200+
tx_buf.len() as core::ffi::c_uint,
201+
rx_buf.as_mut_ptr() as *mut core::ffi::c_void,
202+
rx_buf.len() as core::ffi::c_uint,
203+
)
204+
};
205+
206+
match res {
207+
0 => Ok(()), // 0 indicates a valid transfer,
208+
err => Err(Error::from_errno(err)), // A negative number indicates an error
209+
}
210+
}
211+
212+
/// Corresponds to the kernel's `spi_write`.
213+
///
214+
/// # Examples
215+
///
216+
/// ```
217+
/// let to_write = "rust-for-linux".as_bytes();
218+
///
219+
/// // `spi_device` was previously provided by the kernel in that case
220+
/// let write_result = Spi::write(spi_device, &to_write);
221+
/// ```
222+
pub fn write(dev: &mut SpiDevice, tx_buf: &[u8]) -> Result {
223+
Spi::write_then_read(dev, tx_buf, &mut [0u8; 0])
224+
}
225+
226+
/// Corresponds to the kernel's `spi_read`.
227+
///
228+
/// # Examples
229+
///
230+
/// ```
231+
/// let mut to_receive = [0u8; 10]; // let's receive 10 bytes
232+
///
233+
/// // `spi_device` was previously provided by the kernel in that case
234+
/// let transfer_result = Spi::read(spi_device, &mut to_receive);
235+
/// ```
236+
pub fn read(dev: &mut SpiDevice, rx_buf: &mut [u8]) -> Result {
237+
Spi::write_then_read(dev, &[0u8; 0], rx_buf)
238+
}
239+
}

0 commit comments

Comments
 (0)