Skip to content

Commit c72c3d6

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 165a7fa commit c72c3d6

File tree

3 files changed

+304
-0
lines changed

3 files changed

+304
-0
lines changed

rust/kernel/bindings_helper.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
#include <linux/netfilter_ipv4.h>
3737
#include <linux/netfilter_ipv6.h>
3838
#include <linux/netfilter_arp.h>
39+
#include <linux/platform_device.h>
40+
#include <linux/of_platform.h>
41+
#include <linux/security.h>
42+
#include <asm/io.h>
43+
#include <linux/spi/spi.h>
3944

4045
/* `bindgen` gets confused at certain things. */
4146
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
@@ -107,6 +107,9 @@ pub use crate::types::{
107107

108108
use core::marker::PhantomData;
109109

110+
#[cfg(CONFIG_SPI)]
111+
pub mod spi;
112+
110113
/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
111114
///
112115
/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h

rust/kernel/spi.rs

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
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::{code::*, 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) {}
82+
83+
/// Corresponds to the kernel's `spi_driver`'s `shutdown` method field.
84+
fn shutdown(mut _spi_dev: SpiDevice) {}
85+
}
86+
87+
/// Populate the `TO_USE` field in the [`SpiMethods`] implementer.
88+
///
89+
/// # Examples
90+
///
91+
/// ```
92+
/// impl SpiMethods for MySpiMethods {
93+
/// /// Let's say you only want a probe and remove method, no shutdown.
94+
/// declare_spi_methods!(probe, remove);
95+
///
96+
/// /// Define your probe and remove methods. If you don't, default implementations
97+
/// /// will be used instead. These default implementations do *not* correspond to the
98+
/// /// kernel's default implementations! If you wish to use the kernel's default
99+
/// /// SPI functions implementations, do not declare them using the `declare_spi_methods`
100+
/// /// macro. For example, here our driver will use the kernel's `shutdown` method.
101+
/// fn probe(spi_dev: SpiDevice) -> Result {
102+
/// // ...
103+
///
104+
/// Ok(())
105+
/// }
106+
///
107+
/// fn remove(spi_dev: SpiDevice) -> Result {
108+
/// // ...
109+
///
110+
/// Ok(())
111+
/// }
112+
/// }
113+
/// ```
114+
#[macro_export]
115+
macro_rules! declare_spi_methods {
116+
() => {
117+
const TO_USE: $crate::spi::ToUse = $crate::spi::USE_NONE;
118+
};
119+
($($method:ident),+) => {
120+
const TO_USE: $crate::spi::ToUse = $crate::spi::ToUse {
121+
$($method: true),+,
122+
..$crate::spi::USE_NONE
123+
};
124+
};
125+
}
126+
127+
impl DriverRegistration {
128+
fn new(this_module: &'static crate::ThisModule, name: &'static CStr) -> Self {
129+
DriverRegistration {
130+
this_module,
131+
name,
132+
registered: false,
133+
spi_driver: bindings::spi_driver::default(),
134+
}
135+
}
136+
137+
/// Create a new `DriverRegistration` and register it. This is equivalent to creating
138+
/// a static `spi_driver` and then calling `spi_driver_register` on it in C.
139+
///
140+
/// # Examples
141+
///
142+
/// ```
143+
/// let spi_driver =
144+
/// spi::DriverRegistration::new_pinned::<MySpiMethods>(&THIS_MODULE, cstr!("my_driver_name"))?;
145+
/// ```
146+
pub fn new_pinned<T: SpiMethods>(
147+
this_module: &'static crate::ThisModule,
148+
name: &'static CStr,
149+
) -> Result<Pin<Box<Self>>> {
150+
let mut registration = Pin::from(Box::try_new(Self::new(this_module, name))?);
151+
152+
registration.as_mut().register::<T>()?;
153+
154+
Ok(registration)
155+
}
156+
157+
unsafe extern "C" fn probe_wrapper<T: SpiMethods>(
158+
spi_dev: *mut bindings::spi_device,
159+
) -> c_types::c_int {
160+
// SAFETY: The `spi_dev` pointer is provided by the kernel and is sure to be valid.
161+
match T::probe(unsafe { SpiDevice::from_ptr(spi_dev) }) {
162+
Ok(_) => 0,
163+
Err(e) => e.to_kernel_errno(),
164+
}
165+
}
166+
167+
unsafe extern "C" fn remove_wrapper<T: SpiMethods>(spi_dev: *mut bindings::spi_device) {
168+
// SAFETY: The `spi_dev` pointer is provided by the kernel and is sure to be valid.
169+
T::remove(unsafe { SpiDevice::from_ptr(spi_dev) });
170+
}
171+
172+
unsafe extern "C" fn shutdown_wrapper<T: SpiMethods>(spi_dev: *mut bindings::spi_device) {
173+
// SAFETY: The `spi_dev` pointer is provided by the kernel and is sure to be valid.
174+
T::shutdown(unsafe { SpiDevice::from_ptr(spi_dev) })
175+
}
176+
177+
/// Register a [`DriverRegistration`]. This is equivalent to calling `spi_driver_register`
178+
/// on your `spi_driver` in C, without creating it first.
179+
fn register<T: SpiMethods>(self: Pin<&mut Self>) -> Result {
180+
// SAFETY: We do not move out of the reference we get, and are only registering
181+
// `this` once over the course of the module, since we check that the `registered`
182+
// field was not already set to true.
183+
let this = unsafe { self.get_unchecked_mut() };
184+
if this.registered {
185+
return Err(EINVAL);
186+
}
187+
188+
this.spi_driver.driver.name = this.name.as_ptr() as *const c_types::c_char;
189+
this.spi_driver.probe = T::TO_USE
190+
.probe
191+
.then(|| DriverRegistration::probe_wrapper::<T> as _);
192+
this.spi_driver.remove = T::TO_USE
193+
.remove
194+
.then(|| DriverRegistration::remove_wrapper::<T> as _);
195+
this.spi_driver.shutdown = T::TO_USE
196+
.shutdown
197+
.then(|| DriverRegistration::shutdown_wrapper::<T> as _);
198+
199+
// SAFETY: Since we are using a pinned `self`, we can register the driver safely as
200+
// if we were using a static instance. The kernel will access this driver over the
201+
// entire lifespan of a module and therefore needs a pointer valid for the entirety
202+
// of this lifetime.
203+
let res =
204+
unsafe { bindings::__spi_register_driver(this.this_module.0, &mut this.spi_driver) };
205+
206+
if res != 0 {
207+
return Err(Error::from_kernel_errno(res));
208+
}
209+
210+
this.registered = true;
211+
Ok(())
212+
}
213+
}
214+
215+
impl Drop for DriverRegistration {
216+
fn drop(&mut self) {
217+
// SAFETY: We are simply unregistering an `spi_driver` that we know to be valid.
218+
// [`DriverRegistration`] instances can only be created by being registered at the
219+
// same time, so we are sure that we'll never unregister an unregistered `spi_driver`.
220+
unsafe { bindings::driver_unregister(&mut self.spi_driver.driver) }
221+
}
222+
}
223+
224+
// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
225+
// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
226+
unsafe impl Sync for DriverRegistration {}
227+
228+
// SAFETY: All functions work from any thread.
229+
unsafe impl Send for DriverRegistration {}
230+
231+
/// High level abstraction over the kernel's SPI functions such as `spi_write_then_read`.
232+
pub struct Spi;
233+
234+
impl Spi {
235+
/// Corresponds to the kernel's `spi_write_then_read`.
236+
///
237+
/// # Examples
238+
///
239+
/// ```
240+
/// let to_write = "rust-for-linux".as_bytes();
241+
/// let mut to_receive = [0u8; 10]; // let's receive 10 bytes back
242+
///
243+
/// // `spi_device` was previously provided by the kernel in that case
244+
/// let transfer_result = Spi::write_then_read(spi_device, &to_write, &mut to_receive);
245+
/// ```
246+
pub fn write_then_read(dev: &mut SpiDevice, tx_buf: &[u8], rx_buf: &mut [u8]) -> Result {
247+
// SAFETY: The `dev` argument must uphold the safety guarantees made when creating
248+
// the [`SpiDevice`] instance. It should therefore point to a valid `spi_device`
249+
// and valid memory. We also know that a rust slice will always contain a proper
250+
// size and that it is safe to use as is. Converting from a Rust pointer to a
251+
// generic C `void*` pointer is normal, and does not pose size issues on the
252+
// kernel's side, which will use the given Transfer Receive sizes as bytes.
253+
let res = unsafe {
254+
bindings::spi_write_then_read(
255+
dev.to_ptr(),
256+
tx_buf.as_ptr() as *const c_types::c_void,
257+
tx_buf.len() as c_types::c_uint,
258+
rx_buf.as_mut_ptr() as *mut c_types::c_void,
259+
rx_buf.len() as c_types::c_uint,
260+
)
261+
};
262+
263+
match res {
264+
0 => Ok(()), // 0 indicates a valid transfer,
265+
err => Err(Error::from_kernel_errno(err)), // A negative number indicates an error
266+
}
267+
}
268+
269+
/// Corresponds to the kernel's `spi_write`.
270+
///
271+
/// # Examples
272+
///
273+
/// ```
274+
/// let to_write = "rust-for-linux".as_bytes();
275+
///
276+
/// // `spi_device` was previously provided by the kernel in that case
277+
/// let write_result = Spi::write(spi_device, &to_write);
278+
/// ```
279+
pub fn write(dev: &mut SpiDevice, tx_buf: &[u8]) -> Result {
280+
Spi::write_then_read(dev, tx_buf, &mut [0u8; 0])
281+
}
282+
283+
/// Corresponds to the kernel's `spi_read`.
284+
///
285+
/// # Examples
286+
///
287+
/// ```
288+
/// let mut to_receive = [0u8; 10]; // let's receive 10 bytes
289+
///
290+
/// // `spi_device` was previously provided by the kernel in that case
291+
/// let transfer_result = Spi::read(spi_device, &mut to_receive);
292+
/// ```
293+
pub fn read(dev: &mut SpiDevice, rx_buf: &mut [u8]) -> Result {
294+
Spi::write_then_read(dev, &[0u8; 0], rx_buf)
295+
}
296+
}

0 commit comments

Comments
 (0)