Skip to content

Commit 669248b

Browse files
author
Sven Van Asbroeck
committed
rust/kernel/platdev: add support for device driver data
Device driver data corresponds to per-device context data or state. It is allocated on `probe()` and de-allocated in `remove()`. Signed-off-by: Sven Van Asbroeck <[email protected]>
1 parent cae4454 commit 669248b

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

rust/helpers.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/gfp.h>
88
#include <linux/highmem.h>
99
#include <linux/uio.h>
10+
#include <linux/platform_device.h>
1011

1112
void rust_helper_BUG(void)
1213
{
@@ -117,6 +118,21 @@ long rust_helper_ptr_err(__force const void *ptr)
117118
}
118119
EXPORT_SYMBOL_GPL(rust_helper_ptr_err);
119120

121+
void *
122+
rust_helper_platform_get_drvdata(const struct platform_device *pdev)
123+
{
124+
return platform_get_drvdata(pdev);
125+
}
126+
EXPORT_SYMBOL_GPL(rust_helper_platform_get_drvdata);
127+
128+
void
129+
rust_helper_platform_set_drvdata(struct platform_device *pdev,
130+
void *data)
131+
{
132+
return platform_set_drvdata(pdev, data);
133+
}
134+
EXPORT_SYMBOL_GPL(rust_helper_platform_set_drvdata);
135+
120136
/* We use bindgen's --size_t-is-usize option to bind the C size_t type
121137
* as the Rust usize type, so we can use it in contexts where Rust
122138
* expects a usize like slice (array) indices. usize is defined to be

rust/kernel/platdev.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,31 @@ pub struct Registration {
3030
// (it is fine for multiple threads to have a shared reference to it).
3131
unsafe impl Sync for Registration {}
3232

33+
extern "C" {
34+
#[allow(improper_ctypes)]
35+
fn rust_helper_platform_get_drvdata(
36+
pdev: *const bindings::platform_device,
37+
) -> *mut c_types::c_void;
38+
39+
#[allow(improper_ctypes)]
40+
fn rust_helper_platform_set_drvdata(
41+
pdev: *mut bindings::platform_device,
42+
data: *mut c_types::c_void,
43+
);
44+
}
45+
3346
extern "C" fn probe_callback<P: PlatformDriver>(
3447
pdev: *mut bindings::platform_device,
3548
) -> c_types::c_int {
3649
from_kernel_result! {
3750
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
3851
let device_id = unsafe { (*pdev).id };
39-
P::probe(device_id)?;
52+
let drv_data = P::probe(device_id)?;
53+
let drv_data = drv_data.into_pointer() as *mut c_types::c_void;
54+
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
55+
unsafe {
56+
rust_helper_platform_set_drvdata(pdev, drv_data);
57+
}
4058
Ok(0)
4159
}
4260
}
@@ -47,7 +65,16 @@ extern "C" fn remove_callback<P: PlatformDriver>(
4765
from_kernel_result! {
4866
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
4967
let device_id = unsafe { (*pdev).id };
50-
P::remove(device_id)?;
68+
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
69+
let ptr = unsafe { rust_helper_platform_get_drvdata(pdev) };
70+
// SAFETY:
71+
// - we allocated this pointer using `P::DrvData::into_pointer`,
72+
// so it is safe to turn back into a `P::DrvData`.
73+
// - the allocation happened in `probe`, no-one freed the memory,
74+
// `remove` is the canonical kernel location to free driver data. so OK
75+
// to convert the pointer back to a Rust structure here.
76+
let drv_data = unsafe { P::DrvData::from_pointer(ptr) };
77+
P::remove(device_id, drv_data)?;
5178
Ok(0)
5279
}
5380
}
@@ -124,15 +151,25 @@ impl Drop for Registration {
124151
///
125152
/// Implement this trait whenever you create a platform driver.
126153
pub trait PlatformDriver {
154+
/// Device driver data.
155+
///
156+
/// Corresponds to the data set or retrieved via the kernel's
157+
/// `platform_{set,get}_drvdata()` functions.
158+
///
159+
/// Require that `DrvData` implements `PointerWrapper`. We guarantee to
160+
/// never move the underlying wrapped data structure. This allows
161+
/// driver writers to use pinned or self-referential data structures.
162+
type DrvData: PointerWrapper;
163+
127164
/// Platform driver probe.
128165
///
129166
/// Called when a new platform device is added or discovered.
130167
/// Implementers should attempt to initialize the device here.
131-
fn probe(device_id: i32) -> Result;
168+
fn probe(device_id: i32) -> Result<Self::DrvData>;
132169

133170
/// Platform driver remove.
134171
///
135172
/// Called when a platform device is removed.
136173
/// Implementers should prepare the device for complete removal here.
137-
fn remove(device_id: i32) -> Result;
174+
fn remove(device_id: i32, drv_data: Self::DrvData) -> Result;
138175
}

0 commit comments

Comments
 (0)