Skip to content

Commit 534cfc4

Browse files
committed
platform: move get_id_info from platform.rs to public
Signed-off-by: Li Hongyu <[email protected]>
1 parent f42f82c commit 534cfc4

File tree

3 files changed

+114
-28
lines changed

3 files changed

+114
-28
lines changed

rust/kernel/platform.rs

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ use crate::{
1717
types::PointerWrapper,
1818
ThisModule,
1919
};
20+
use macros::GetIdInfo;
2021

2122
/// A registration of a platform driver.
2223
pub type Registration<T> = driver::Registration<Adapter<T>>;
2324

2425
/// An adapter for the registration of platform drivers.
26+
#[derive(GetIdInfo)]
2527
pub struct Adapter<T: Driver>(T);
2628

2729
impl<T: Driver> driver::DriverOps for Adapter<T> {
@@ -61,34 +63,6 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
6163
}
6264

6365
impl<T: Driver> Adapter<T> {
64-
fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
65-
let table = T::OF_DEVICE_ID_TABLE?;
66-
67-
// SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
68-
// valid while it's alive, so is the raw device returned by it.
69-
let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
70-
if id.is_null() {
71-
return None;
72-
}
73-
74-
// SAFETY: `id` is a pointer within the static table, so it's always valid.
75-
let offset = unsafe { (*id).data };
76-
if offset.is_null() {
77-
return None;
78-
}
79-
80-
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
81-
// guarantees that the resulting pointer is within the table.
82-
let ptr = unsafe {
83-
id.cast::<u8>()
84-
.offset(offset as _)
85-
.cast::<Option<T::IdInfo>>()
86-
};
87-
88-
// SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
89-
unsafe { (&*ptr).as_ref() }
90-
}
91-
9266
extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> core::ffi::c_int {
9367
from_kernel_result! {
9468
// SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the

rust/macros/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
mod concat_idents;
66
mod helpers;
77
mod module;
8+
mod of_id;
89
mod vtable;
910

1011
use proc_macro::TokenStream;
@@ -188,3 +189,44 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
188189
pub fn concat_idents(ts: TokenStream) -> TokenStream {
189190
concat_idents::concat_idents(ts)
190191
}
192+
193+
/// Implements a get_id_info function for drivers.
194+
///
195+
/// Some linux drivers, e.g. Platform drivers, need to get info from of_id. This macro helps implements the get_id_info
196+
/// function for those drivers.
197+
///
198+
/// # Examples
199+
///
200+
/// ```ignore
201+
/// use crate::{
202+
/// bindings,
203+
/// device::{self, RawDevice},
204+
/// driver,
205+
/// of,
206+
/// };
207+
///
208+
/// pub trait Driver {
209+
/// type IdInfo: 'static = ();
210+
/// const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
211+
/// }
212+
///
213+
/// pub struct Device {
214+
/// ptr: *mut bindings::bar_device,
215+
/// }
216+
///
217+
/// // SAFETY: The device returned by `raw_device` is the raw bar device.
218+
/// unsafe impl device::RawDevice for Device {
219+
/// fn raw_device(&self) -> *mut bindings::device {
220+
/// // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
221+
/// unsafe { &mut (*self.ptr).dev }
222+
/// }
223+
/// }
224+
///
225+
/// // Implements a `#[GetIdInfo]` function
226+
/// #[derive(GetIdInfo)]
227+
/// pub struct Foo<T: Driver>(T);
228+
/// ```
229+
#[proc_macro_derive(GetIdInfo)]
230+
pub fn derive_get_id_info(ts: TokenStream) -> TokenStream {
231+
of_id::derive_get_id_info(ts)
232+
}

rust/macros/of_id.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use proc_macro::{TokenStream, TokenTree};
4+
5+
pub(crate) fn derive_get_id_info(ts: TokenStream) -> TokenStream {
6+
let tokens: Vec<_> = ts.into_iter().collect();
7+
let mut type_name = String::from("Struct");
8+
9+
tokens
10+
.iter()
11+
.find_map(|token| match token {
12+
TokenTree::Ident(ident) => match ident.to_string().as_str() {
13+
"struct" => Some(1),
14+
_ => None,
15+
},
16+
_ => None,
17+
})
18+
.expect("#[GetIdInfo] should be applied to a struct");
19+
20+
let mut content = tokens.into_iter();
21+
while let Some(token) = content.next() {
22+
match token {
23+
TokenTree::Ident(ident) if ident.to_string() == "struct" => {
24+
match content.next() {
25+
Some(TokenTree::Ident(ident)) => type_name = ident.to_string(),
26+
// This will never happend.
27+
_ => (),
28+
};
29+
}
30+
_ => (),
31+
}
32+
}
33+
34+
println!("value {:?}", type_name);
35+
36+
format!(
37+
"
38+
impl<T: Driver> {name}<T> {{
39+
fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {{
40+
let table = T::OF_DEVICE_ID_TABLE?;
41+
42+
// SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
43+
// valid while it's alive, so is the raw device returned by it.
44+
let id = unsafe {{ bindings::of_match_device(table.as_ref(), dev.raw_device()) }};
45+
if id.is_null() {{
46+
return None;
47+
}}
48+
49+
// SAFETY: `id` is a pointer within the static table, so it's always valid.
50+
let offset = unsafe {{ (*id).data }};
51+
if offset.is_null() {{
52+
return None;
53+
}}
54+
55+
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
56+
// guarantees that the resulting pointer is within the table.
57+
let ptr = unsafe {{
58+
id.cast::<u8>()
59+
.offset(offset as _)
60+
.cast::<Option<T::IdInfo>>()
61+
}};
62+
63+
// SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
64+
unsafe {{ (&*ptr).as_ref() }}
65+
}}
66+
}}
67+
",
68+
name = type_name,
69+
).parse().expect("Error parsing formatted string into token stream.")
70+
}

0 commit comments

Comments
 (0)