//! [`device_id`]: kernel::device_id
//! [`module_driver`]: kernel::module_driver
-use crate::error::{Error, Result};
-use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule};
-use core::pin::Pin;
-use pin_init::{pin_data, pinned_drop, PinInit};
+use crate::{
+ acpi,
+ device,
+ of,
+ prelude::*,
+ types::Opaque,
+ ThisModule, //
+};
+ /// Trait describing the layout of a specific device driver.
+ ///
+ /// This trait describes the layout of a specific driver structure, such as `struct pci_driver` or
+ /// `struct platform_driver`.
+ ///
+ /// # Safety
+ ///
+ /// Implementors must guarantee that:
+ /// - `DriverType` is `repr(C)`,
+ /// - `DriverData` is the type of the driver's device private data.
+ /// - `DriverType` embeds a valid `struct device_driver` at byte offset `DEVICE_DRIVER_OFFSET`.
+ pub unsafe trait DriverLayout {
+ /// The specific driver type embedding a `struct device_driver`.
+ type DriverType: Default;
+
+ /// The type of the driver's device private data.
+ type DriverData;
+
+ /// Byte offset of the embedded `struct device_driver` within `DriverType`.
+ ///
+ /// This must correspond exactly to the location of the embedded `struct device_driver` field.
+ const DEVICE_DRIVER_OFFSET: usize;
+ }
+
/// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform,
/// Amba, etc.) to provide the corresponding subsystem specific implementation to register /
- /// unregister a driver of the particular type (`RegType`).
+ /// unregister a driver of the particular type (`DriverType`).
///
- /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call
+ /// For instance, the PCI subsystem would set `DriverType` to `bindings::pci_driver` and call
/// `bindings::__pci_register_driver` from `RegistrationOps::register` and
/// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`.
///
/// Bound checks are performed on compile time, hence if the offset is not known at compile
/// time, the build will fail.
$(#[$attr])*
- #[inline]
+ // Always inline to optimize out error path of `io_addr_assert`.
+ #[inline(always)]
- pub fn $name(&self, offset: usize) -> $type_name {
+ $vis fn $name(&self, offset: usize) -> $type_name {
let addr = self.io_addr_assert::<$type_name>(offset);
- // SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
- unsafe { bindings::$c_fn(addr as *const c_void) }
+ // SAFETY: By the type invariant `addr` is a valid address for IO operations.
+ $call_macro!(infallible, $c_fn, self, $type_name, addr)
}
+ };
+ (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) ->
+ $type_name:ty) => {
/// Read IO data from a given offset.
///
/// Bound checks are performed on runtime, it fails if the offset (plus the type size) is
/// Bound checks are performed on compile time, hence if the offset is not known at compile
/// time, the build will fail.
$(#[$attr])*
- #[inline]
+ // Always inline to optimize out error path of `io_addr_assert`.
+ #[inline(always)]
- pub fn $name(&self, value: $type_name, offset: usize) {
+ $vis fn $name(&self, value: $type_name, offset: usize) {
let addr = self.io_addr_assert::<$type_name>(offset);
- // SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
- unsafe { bindings::$c_fn(value, addr as *mut c_void) }
+ $call_macro!(infallible, $c_fn, self, $type_name, addr, value);
}
+ };
+ (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) <-
+ $type_name:ty) => {
/// Write IO data from a given offset.
///
/// Bound checks are performed on runtime, it fails if the offset (plus the type size) is
self.addr().checked_add(offset).ok_or(EINVAL)
}
- #[inline]
+ /// Returns the absolute I/O address for a given `offset`,
+ /// performing compile-time bound checks.
+ // Always inline to optimize out error path of `build_assert`.
+ #[inline(always)]
fn io_addr_assert<U>(&self, offset: usize) -> usize {
- build_assert!(Self::offset_valid::<U>(offset, SIZE));
+ build_assert!(offset_valid::<U>(offset, Self::MIN_SIZE));
self.addr() + offset
}