Skip to content

Commit c13e4d1

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

File tree

2 files changed

+95
-33
lines changed

2 files changed

+95
-33
lines changed

rust/kernel/driver.rs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
66
//! using the [`Registration`] class.
77
8-
use crate::{error::code::*, str::CStr, sync::Ref, Result, ThisModule};
8+
use crate::{
9+
device::RawDevice, driver, error::code::*, of, str::CStr, sync::Ref, Result, ThisModule,
10+
};
911
use alloc::boxed::Box;
1012
use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
1113

@@ -440,3 +442,93 @@ macro_rules! module_driver {
440442
}
441443
}
442444
}
445+
446+
/// Get info from `of_id`.
447+
///
448+
/// Some kinds of drivers, e.g. Platform drivers, need to get info from `of_id`.
449+
/// This function achieves this goal.
450+
///
451+
/// # Examples
452+
///
453+
/// ```ignore
454+
/// use crate::{
455+
/// bindings,
456+
/// device::RawDevice,
457+
/// driver,
458+
/// error::from_kernel_result,
459+
/// of,
460+
/// };
461+
///
462+
/// pub trait Driver {
463+
/// type IdInfo: 'static = ();
464+
/// const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
465+
/// }
466+
///
467+
/// pub struct Device {
468+
/// ptr: *mut bindings::bar_device,
469+
/// }
470+
///
471+
/// impl Device {
472+
/// /// Creates a new device from the given pointer.
473+
/// ///
474+
/// /// # Safety
475+
/// ///
476+
/// /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the
477+
/// /// returned instance.
478+
/// unsafe fn from_ptr(ptr: *mut bindings::bar_device) -> Self {
479+
/// // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
480+
/// Self { ptr }
481+
/// }
482+
/// }
483+
///
484+
/// // SAFETY: The device returned by `raw_device` is the raw bar device.
485+
/// unsafe impl device::RawDevice for Device {
486+
/// fn raw_device(&self) -> *mut bindings::device {
487+
/// // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
488+
/// unsafe { &mut (*self.ptr).dev }
489+
/// }
490+
/// }
491+
///
492+
/// pub struct Foo<T: Driver>(T);
493+
///
494+
/// impl<T: Driver> Adapter<T> {
495+
/// extern "C" fn probe_callback(pdev: *mut bindings::bar_device) -> core::ffi::c_int {
496+
/// from_kernel_result! {
497+
/// // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for
498+
/// // the duration of this call, so it is guaranteed to remain alive for the lifetime
499+
/// // of `pdev`.
500+
/// let mut dev = unsafe { Device::from_ptr(pdev) };
501+
/// // Use `get_id_info` to get info from `of_id`
502+
/// let info = driver::get_id_info(&dev, T::OF_DEVICE_ID_TABLE);
503+
/// let data = T::probe(&mut dev, info)?;
504+
/// Ok(0)
505+
/// }
506+
/// }
507+
/// }
508+
/// ```
509+
pub fn get_id_info<T>(
510+
dev: &impl RawDevice,
511+
table: Option<driver::IdTable<'static, of::DeviceId, T>>,
512+
) -> Option<&'static T> {
513+
let table = table?;
514+
515+
// SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
516+
// valid while it's alive, so is the raw device returned by it.
517+
let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
518+
if id.is_null() {
519+
return None;
520+
}
521+
522+
// SAFETY: `id` is a pointer within the static table, so it's always valid.
523+
let offset = unsafe { (*id).data };
524+
if offset.is_null() {
525+
return None;
526+
}
527+
528+
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
529+
// guarantees that the resulting pointer is within the table.
530+
let ptr = unsafe { id.cast::<u8>().offset(offset as _).cast::<Option<T>>() };
531+
532+
// SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
533+
unsafe { (&*ptr).as_ref() }
534+
}

rust/kernel/platform.rs

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
88
99
use crate::{
10-
bindings,
11-
device::{self, RawDevice},
12-
driver,
10+
bindings, device, driver,
1311
error::{from_kernel_result, Result},
1412
of,
1513
str::CStr,
@@ -61,41 +59,13 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
6159
}
6260

6361
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-
9262
extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> core::ffi::c_int {
9363
from_kernel_result! {
9464
// SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
9565
// duration of this call, so it is guaranteed to remain alive for the lifetime of
9666
// `pdev`.
9767
let mut dev = unsafe { Device::from_ptr(pdev) };
98-
let info = Self::get_id_info(&dev);
68+
let info = driver::get_id_info(&dev, T::OF_DEVICE_ID_TABLE);
9969
let data = T::probe(&mut dev, info)?;
10070
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
10171
unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };

0 commit comments

Comments
 (0)