Skip to content

Commit ee54914

Browse files
author
Sven Van Asbroeck
committed
Add support for "platform devices" to the Rust kernel core
Implements the bare minimum required to register a platform device with the kernel. Registered devices won't actually be able to do anything. Registered platform devices will be visible in sysfs, under /sys/bus/platform/{devices,drivers}/ Signed-off-by: Sven Van Asbroeck <[email protected]>
1 parent fc2b177 commit ee54914

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

rust/kernel/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/poll.h>
1414
#include <linux/mm.h>
1515
#include <uapi/linux/android/binder.h>
16+
#include <linux/platform_device.h>
1617

1718
// `bindgen` gets confused at certain things
1819
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub mod sysctl;
6262

6363
pub mod io_buffer;
6464
pub mod iov_iter;
65+
pub mod platdev;
6566
mod types;
6667
pub mod user_ptr;
6768

rust/kernel/platdev.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Platform devices.
4+
//!
5+
//! Also called `platdev`, `pdev`.
6+
//!
7+
//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
8+
9+
use crate::{
10+
bindings, c_types,
11+
error::{Error, Result},
12+
pr_info, CStr,
13+
};
14+
use alloc::boxed::Box;
15+
use core::{marker::PhantomPinned, pin::Pin};
16+
17+
/// A registration of a platform device.
18+
#[derive(Default)]
19+
pub struct Registration {
20+
registered: bool,
21+
pdrv: bindings::platform_driver,
22+
_pin: PhantomPinned,
23+
}
24+
25+
// SAFETY: `Registration` does not expose any of its state across threads
26+
// (it is fine for multiple threads to have a shared reference to it).
27+
unsafe impl Sync for Registration {}
28+
29+
extern "C" fn probe_callback(_pdev: *mut bindings::platform_device) -> c_types::c_int {
30+
pr_info!("Rust platform_device probed\n");
31+
0
32+
}
33+
34+
extern "C" fn remove_callback(_pdev: *mut bindings::platform_device) -> c_types::c_int {
35+
pr_info!("Rust platform_device removed\n");
36+
0
37+
}
38+
39+
impl Registration {
40+
fn register(
41+
self: Pin<&mut Self>,
42+
name: CStr<'static>,
43+
module: &'static crate::ThisModule,
44+
) -> Result {
45+
// SAFETY: We must ensure that we never move out of `this`.
46+
let this = unsafe { self.get_unchecked_mut() };
47+
if this.registered {
48+
// Already registered.
49+
return Err(Error::EINVAL);
50+
}
51+
this.pdrv.driver.name = name.as_ptr() as *const c_types::c_char;
52+
this.pdrv.probe = Some(probe_callback);
53+
this.pdrv.remove = Some(remove_callback);
54+
// SAFETY:
55+
// - `this.pdrv` lives at least until the call to `platform_driver_unregister()` returns.
56+
// - `name` pointer has static lifetime.
57+
// - `module.0` lives as least as long as the module.
58+
// - `probe()` and `remove()` are static functions.
59+
// So `bindings::__platform_driver_register()` is safe to call.
60+
let ret = unsafe { bindings::__platform_driver_register(&mut this.pdrv, module.0) };
61+
if ret < 0 {
62+
return Err(Error::from_kernel_errno(ret));
63+
}
64+
this.registered = true;
65+
Ok(())
66+
}
67+
68+
/// Registers a platform device.
69+
///
70+
/// Returns a pinned heap-allocated representation of the registration.
71+
pub fn new_pinned(
72+
name: CStr<'static>,
73+
module: &'static crate::ThisModule,
74+
) -> Result<Pin<Box<Self>>> {
75+
let mut r = Pin::from(Box::try_new(Self::default())?);
76+
r.as_mut().register(name, module)?;
77+
Ok(r)
78+
}
79+
}
80+
81+
impl Drop for Registration {
82+
fn drop(&mut self) {
83+
if self.registered {
84+
// SAFETY: if `registered` is true, then `self.pdev` was registered
85+
// previously, which means `platform_driver_unregister` is always
86+
// safe to call.
87+
unsafe { bindings::platform_driver_unregister(&mut self.pdrv) }
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)