forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathplatdev.rs
More file actions
109 lines (100 loc) · 3.53 KB
/
platdev.rs
File metadata and controls
109 lines (100 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// SPDX-License-Identifier: GPL-2.0
//! Platform devices.
//!
//! Also called `platdev`, `pdev`.
//!
//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
use crate::{
bindings, c_types,
error::{Error, Result},
of::OfMatchTable,
pr_info,
str::CStr,
types::PointerWrapper,
};
use alloc::boxed::Box;
use core::{marker::PhantomPinned, pin::Pin};
/// A registration of a platform device.
#[derive(Default)]
pub struct Registration {
registered: bool,
of_table: Option<*const c_types::c_void>,
pdrv: bindings::platform_driver,
_pin: PhantomPinned,
}
// SAFETY: `Registration` does not expose any of its state across threads
// (it is fine for multiple threads to have a shared reference to it).
unsafe impl Sync for Registration {}
extern "C" fn probe_callback(_pdev: *mut bindings::platform_device) -> c_types::c_int {
pr_info!("Rust platform_device probed\n");
0
}
extern "C" fn remove_callback(_pdev: *mut bindings::platform_device) -> c_types::c_int {
pr_info!("Rust platform_device removed\n");
0
}
impl Registration {
fn register(
self: Pin<&mut Self>,
name: &'static CStr,
of_match_table: Option<OfMatchTable>,
module: &'static crate::ThisModule,
) -> Result {
// SAFETY: We must ensure that we never move out of `this`.
let this = unsafe { self.get_unchecked_mut() };
if this.registered {
// Already registered.
return Err(Error::EINVAL);
}
this.pdrv.driver.name = name.as_char_ptr();
if let Some(tbl) = of_match_table {
let ptr = tbl.into_pointer();
this.of_table = Some(ptr);
this.pdrv.driver.of_match_table = ptr.cast();
}
this.pdrv.probe = Some(probe_callback);
this.pdrv.remove = Some(remove_callback);
// SAFETY:
// - `this.pdrv` lives at least until the call to `platform_driver_unregister()` returns.
// - `name` pointer has static lifetime.
// - `module.0` lives at least as long as the module.
// - `probe()` and `remove()` are static functions.
// - `of_match_table` is either:
// - a raw pointer which lives until after the call to
// `bindings::platform_driver_unregister()`, or
// - null.
let ret = unsafe { bindings::__platform_driver_register(&mut this.pdrv, module.0) };
if ret < 0 {
return Err(Error::from_kernel_errno(ret));
}
this.registered = true;
Ok(())
}
/// Registers a platform device.
///
/// Returns a pinned heap-allocated representation of the registration.
pub fn new_pinned(
name: &'static CStr,
of_match_tbl: Option<OfMatchTable>,
module: &'static crate::ThisModule,
) -> Result<Pin<Box<Self>>> {
let mut r = Pin::from(Box::try_new(Self::default())?);
r.as_mut().register(name, of_match_tbl, module)?;
Ok(r)
}
}
impl Drop for Registration {
fn drop(&mut self) {
if self.registered {
// SAFETY: if `registered` is true, then `self.pdev` was registered
// previously, which means `platform_driver_unregister` is always
// safe to call.
unsafe { bindings::platform_driver_unregister(&mut self.pdrv) }
}
if let Some(ptr) = self.of_table {
// SAFETY: `ptr` came from an `OfMatchTable`.
let tbl = unsafe { OfMatchTable::from_pointer(ptr) };
drop(tbl);
}
}
}