|
5 | 5 | //! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
|
6 | 6 | //! using the [`Registration`] class.
|
7 | 7 |
|
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 | +}; |
9 | 11 | use alloc::boxed::Box;
|
10 | 12 | use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
|
11 | 13 |
|
@@ -440,3 +442,93 @@ macro_rules! module_driver {
|
440 | 442 | }
|
441 | 443 | }
|
442 | 444 | }
|
| 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::{self, 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 | +} |
0 commit comments