summaryrefslogtreecommitdiff
path: root/rust/kernel/device.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/kernel/device.rs')
-rw-r--r--rust/kernel/device.rs91
1 files changed, 60 insertions, 31 deletions
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index 645afc49a27d..2291d85b6849 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -54,7 +54,8 @@ pub mod property;
/// reference is valid in. For instance, the [`Bound`] context guarantees that the [`Device`] is
/// bound to a driver for the entire duration of the existence of a [`Device<Bound>`] reference.
///
-/// Other [`DeviceContext`] types besides [`Bound`] are [`Normal`], [`Core`] and [`CoreInternal`].
+/// Other [`DeviceContext`] types besides [`Bound`] are [`Normal`], [`Core`], [`CoreInternal`] and
+/// [`BoundInternal`].
///
/// Unless selected otherwise [`Device`] defaults to the [`Normal`] [`DeviceContext`], which by
/// itself has no additional requirements.
@@ -235,7 +236,9 @@ impl<'a> Device<CoreInternal<'a>> {
// in `into_foreign()`.
Some(unsafe { Pin::<KBox<T>>::from_foreign(ptr.cast()) })
}
+}
+impl<Ctx: InternalBoundContext> Device<Ctx> {
/// Borrow the driver's private data bound to this [`Device`].
///
/// # Safety
@@ -245,22 +248,6 @@ impl<'a> Device<CoreInternal<'a>> {
/// - The type `T` must match the type of the `ForeignOwnable` previously stored by
/// [`Device::set_drvdata`].
pub unsafe fn drvdata_borrow<T>(&self) -> Pin<&T> {
- // SAFETY: `drvdata_unchecked()` has the exact same safety requirements as the ones
- // required by this method.
- unsafe { self.drvdata_unchecked() }
- }
-}
-
-impl Device<Bound> {
- /// Borrow the driver's private data bound to this [`Device`].
- ///
- /// # Safety
- ///
- /// - Must only be called after a preceding call to [`Device::set_drvdata`] and before
- /// the device is fully unbound.
- /// - The type `T` must match the type of the `ForeignOwnable` previously stored by
- /// [`Device::set_drvdata`].
- unsafe fn drvdata_unchecked<T>(&self) -> Pin<&T> {
// SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`.
let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) };
@@ -476,7 +463,8 @@ unsafe impl Sync for Device<Bound> {}
/// [`DeviceContext`] is a marker trait for types representing the context of a bus specific
/// [`Device`].
///
-/// The specific device context types are: [`CoreInternal`], [`Core`], [`Bound`] and [`Normal`].
+/// The specific device context types are: [`CoreInternal`], [`Core`], [`BoundInternal`], [`Bound`]
+/// and [`Normal`].
///
/// [`DeviceContext`] types are hierarchical, which means that there is a strict hierarchy that
/// defines which [`DeviceContext`] type can be derived from another. For instance, any
@@ -485,6 +473,11 @@ unsafe impl Sync for Device<Bound> {}
/// The following enumeration illustrates the dereference hierarchy of [`DeviceContext`] types.
///
/// - [`CoreInternal`] => [`Core`] => [`Bound`] => [`Normal`]
+/// - [`BoundInternal`] => [`Bound`] => [`Normal`]
+///
+/// Both [`CoreInternal`] and [`BoundInternal`] implement the [`InternalBoundContext`] trait,
+/// which provides access to internal bus abstraction methods on [`Device`] that are not available
+/// to drivers.
///
/// Bus devices can automatically implement the dereference hierarchy by using
/// [`impl_device_context_deref`].
@@ -511,7 +504,11 @@ pub struct Normal;
/// callback it appears in. It is intended to be used for synchronization purposes. Bus device
/// implementations can implement methods for [`Device<Core>`], such that they can only be called
/// from bus callbacks.
-pub struct Core<'a>(PhantomData<&'a ()>);
+///
+/// The lifetime `'a` is for "lifetime branding" purpose. Callbacks need to polymorphic over this
+/// lifetime so the `&'bound Device<Core<'_>>` provided to them cannot outlive the scope of the
+/// function. For this reason, it needs to be invariant.
+pub struct Core<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
/// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus
/// abstraction.
@@ -522,7 +519,21 @@ pub struct Core<'a>(PhantomData<&'a ()>);
///
/// This context mainly exists to share generic [`Device`] infrastructure that should only be called
/// from bus callbacks with bus abstractions, but without making them accessible for drivers.
-pub struct CoreInternal<'a>(PhantomData<&'a ()>);
+///
+/// Lifetime `'a` is invariant for the same reason as [`Core`].
+pub struct CoreInternal<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
+
+/// Semantically the same as [`Bound`], but reserved for internal usage of the corresponding bus
+/// abstraction.
+///
+/// The internal bound context is intended to be used in exactly the same way as the [`Bound`]
+/// context, with the difference that this [`DeviceContext`] is internal to the corresponding bus
+/// abstraction.
+///
+/// This context exists for cases where the bus abstraction needs access to internal device
+/// infrastructure (such as [`Device::drvdata_borrow`]), where [`CoreInternal`] would not be
+/// justified.
+pub struct BoundInternal;
/// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to
/// be bound to a driver.
@@ -546,16 +557,28 @@ mod private {
pub trait Sealed {}
impl Sealed for super::Bound {}
+ impl Sealed for super::BoundInternal {}
impl<'a> Sealed for super::Core<'a> {}
impl<'a> Sealed for super::CoreInternal<'a> {}
impl Sealed for super::Normal {}
}
impl DeviceContext for Bound {}
+impl DeviceContext for BoundInternal {}
impl<'a> DeviceContext for Core<'a> {}
impl<'a> DeviceContext for CoreInternal<'a> {}
impl DeviceContext for Normal {}
+/// Marker trait for [`DeviceContext`] types that have internal bound-level access.
+///
+/// This trait is implemented by [`CoreInternal`] and [`BoundInternal`], allowing methods that
+/// require internal bus abstraction access to a bound device to be generic over both contexts.
+///
+/// Methods bounded by this trait are available to bus abstractions but not to drivers.
+pub trait InternalBoundContext: DeviceContext {}
+impl<'a> InternalBoundContext for CoreInternal<'a> {}
+impl InternalBoundContext for BoundInternal {}
+
impl<Ctx: DeviceContext> AsRef<Device<Ctx>> for Device<Ctx> {
#[inline]
fn as_ref(&self) -> &Device<Ctx> {
@@ -665,6 +688,13 @@ macro_rules! impl_device_context_deref {
// `__impl_device_context_deref!`.
::kernel::__impl_device_context_deref!(unsafe {
$device,
+ $crate::device::BoundInternal => $crate::device::Bound
+ });
+
+ // SAFETY: This macro has the exact same safety requirement as
+ // `__impl_device_context_deref!`.
+ ::kernel::__impl_device_context_deref!(unsafe {
+ $device,
$crate::device::Bound => $crate::device::Normal
});
};
@@ -700,6 +730,7 @@ macro_rules! impl_device_context_into_aref {
::kernel::__impl_device_context_into_aref!(
<'a> $crate::device::Core<'a>, $device
);
+ ::kernel::__impl_device_context_into_aref!($crate::device::BoundInternal, $device);
::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device);
};
}
@@ -708,9 +739,7 @@ macro_rules! impl_device_context_into_aref {
#[macro_export]
macro_rules! dev_printk {
($method:ident, $dev:expr, $($f:tt)*) => {
- {
- $crate::device::Device::$method($dev.as_ref(), $crate::prelude::fmt!($($f)*))
- }
+ $crate::device::Device::$method($dev.as_ref(), $crate::prelude::fmt!($($f)*))
}
}
@@ -737,7 +766,7 @@ macro_rules! dev_printk {
/// ```
#[macro_export]
macro_rules! dev_emerg {
- ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*) }
}
/// Prints an alert-level message (level 1) prefixed with device information.
@@ -763,7 +792,7 @@ macro_rules! dev_emerg {
/// ```
#[macro_export]
macro_rules! dev_alert {
- ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*) }
}
/// Prints a critical-level message (level 2) prefixed with device information.
@@ -789,7 +818,7 @@ macro_rules! dev_alert {
/// ```
#[macro_export]
macro_rules! dev_crit {
- ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*) }
}
/// Prints an error-level message (level 3) prefixed with device information.
@@ -815,7 +844,7 @@ macro_rules! dev_crit {
/// ```
#[macro_export]
macro_rules! dev_err {
- ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*) }
}
/// Prints a warning-level message (level 4) prefixed with device information.
@@ -841,7 +870,7 @@ macro_rules! dev_err {
/// ```
#[macro_export]
macro_rules! dev_warn {
- ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*) }
}
/// Prints a notice-level message (level 5) prefixed with device information.
@@ -867,7 +896,7 @@ macro_rules! dev_warn {
/// ```
#[macro_export]
macro_rules! dev_notice {
- ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*) }
}
/// Prints an info-level message (level 6) prefixed with device information.
@@ -893,7 +922,7 @@ macro_rules! dev_notice {
/// ```
#[macro_export]
macro_rules! dev_info {
- ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*) }
}
/// Prints a debug-level message (level 7) prefixed with device information.
@@ -919,5 +948,5 @@ macro_rules! dev_info {
/// ```
#[macro_export]
macro_rules! dev_dbg {
- ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+ ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*) }
}