]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rust: Add trait to convert a device reference to a bus device reference
authorMarkus Probst <markus.probst@posteo.de>
Mon, 27 Oct 2025 20:06:03 +0000 (20:06 +0000)
committerDanilo Krummrich <dakr@kernel.org>
Mon, 17 Nov 2025 22:00:51 +0000 (11:00 +1300)
Implement the `AsBusDevice` trait for converting a `Device` reference to a
bus device reference for all bus devices.

The `AsBusDevice` trait allows abstractions to provide the bus device in
class device callbacks. It must not be used by drivers and is intended for
bus and class device abstractions only.

Signed-off-by: Markus Probst <markus.probst@posteo.de>
Link: https://patch.msgid.link/20251027200547.1038967-2-markus.probst@posteo.de
[ * Remove unused import.
  * Change visibility of AsBusDevice to public.
  * Fix build for USB.
  * Add impl for I2cClient.
  - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
rust/kernel/auxiliary.rs
rust/kernel/device.rs
rust/kernel/i2c.rs
rust/kernel/pci.rs
rust/kernel/platform.rs
rust/kernel/usb.rs

index 618eeeec2bd092e7faf2769cb7e0f21e854b4297..56f3c180e8f694d5c9d6da8bb9147a047cfbd750 100644 (file)
@@ -16,6 +16,7 @@ use crate::{
 };
 use core::{
     marker::PhantomData,
+    mem::offset_of,
     ptr::{addr_of_mut, NonNull},
 };
 
@@ -245,6 +246,12 @@ impl Device {
     }
 }
 
+// SAFETY: `auxiliary::Device` is a transparent wrapper of `struct auxiliary_device`.
+// The offset is guaranteed to point to a valid device field inside `auxiliary::Device`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::auxiliary_device, dev);
+}
+
 // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
 // argument.
 kernel::impl_device_context_deref!(unsafe { Device });
index 1a307be953c2585478a1c9f43c8d6ebdb02c499c..660cb2b48c0741e26fbd8ac60957deed165a6a44 100644 (file)
@@ -594,6 +594,39 @@ impl DeviceContext for Core {}
 impl DeviceContext for CoreInternal {}
 impl DeviceContext for Normal {}
 
+/// Convert device references to bus device references.
+///
+/// Bus devices can implement this trait to allow abstractions to provide the bus device in
+/// class device callbacks.
+///
+/// This must not be used by drivers and is intended for bus and class device abstractions only.
+///
+/// # Safety
+///
+/// `AsBusDevice::OFFSET` must be the offset of the embedded base `struct device` field within a
+/// bus device structure.
+pub unsafe trait AsBusDevice<Ctx: DeviceContext>: AsRef<Device<Ctx>> {
+    /// The relative offset to the device field.
+    ///
+    /// Use `offset_of!(bindings, field)` macro to avoid breakage.
+    const OFFSET: usize;
+
+    /// Convert a reference to [`Device`] into `Self`.
+    ///
+    /// # Safety
+    ///
+    /// `dev` must be contained in `Self`.
+    unsafe fn from_device(dev: &Device<Ctx>) -> &Self
+    where
+        Self: Sized,
+    {
+        let raw = dev.as_raw();
+        // SAFETY: `raw - Self::OFFSET` is guaranteed by the safety requirements
+        // to be a valid pointer to `Self`.
+        unsafe { &*raw.byte_sub(Self::OFFSET).cast::<Self>() }
+    }
+}
+
 /// # Safety
 ///
 /// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
index aea1b44d189bbc769da77a76262c065217f2ecd6..95b056cc1a715b1fbdc92875c108bd8116657283 100644 (file)
@@ -24,6 +24,7 @@ use crate::{
 
 use core::{
     marker::PhantomData,
+    mem::offset_of,
     ptr::{
         from_ref,
         NonNull, //
@@ -476,6 +477,12 @@ impl<Ctx: device::DeviceContext> I2cClient<Ctx> {
     }
 }
 
+// SAFETY: `I2cClient` is a transparent wrapper of `struct i2c_client`.
+// The offset is guaranteed to point to a valid device field inside `I2cClient`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for I2cClient<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::i2c_client, dev);
+}
+
 // SAFETY: `I2cClient` is a transparent wrapper of a type that doesn't depend on
 // `I2cClient`'s generic argument.
 kernel::impl_device_context_deref!(unsafe { I2cClient });
index 410b79d4663291b9628833b8e2c37e4a909c29f6..82e128431f080fde78a06dc5c284ab12739e747e 100644 (file)
@@ -24,6 +24,7 @@ use crate::{
 };
 use core::{
     marker::PhantomData,
+    mem::offset_of,
     ptr::{
         addr_of_mut,
         NonNull, //
@@ -443,6 +444,12 @@ impl Device<device::Core> {
     }
 }
 
+// SAFETY: `pci::Device` is a transparent wrapper of `struct pci_dev`.
+// The offset is guaranteed to point to a valid device field inside `pci::Device`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::pci_dev, dev);
+}
+
 // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
 // argument.
 kernel::impl_device_context_deref!(unsafe { Device });
index f4b617c570be53d0d873ea521c705033b3e24606..ed889f079cab6072994eb8f06da73d4b9c9b3492 100644 (file)
@@ -19,6 +19,7 @@ use crate::{
 
 use core::{
     marker::PhantomData,
+    mem::offset_of,
     ptr::{addr_of_mut, NonNull},
 };
 
@@ -287,6 +288,12 @@ impl Device<Bound> {
     }
 }
 
+// SAFETY: `platform::Device` is a transparent wrapper of `struct platform_device`.
+// The offset is guaranteed to point to a valid device field inside `platform::Device`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::platform_device, dev);
+}
+
 macro_rules! define_irq_accessor_by_index {
     (
         $(#[$meta:meta])* $fn_name:ident,
index 534e3ded54420ef0036e36f77af1aabdc6090060..d10b65e9fb6adcacc2aa93a034eb6d213da4e744 100644 (file)
@@ -15,7 +15,14 @@ use crate::{
     types::{AlwaysRefCounted, Opaque},
     ThisModule,
 };
-use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
+use core::{
+    marker::PhantomData,
+    mem::{
+        offset_of,
+        MaybeUninit, //
+    },
+    ptr::NonNull,
+};
 
 /// An adapter for the registration of USB drivers.
 pub struct Adapter<T: Driver>(T);
@@ -324,6 +331,12 @@ impl<Ctx: device::DeviceContext> Interface<Ctx> {
     }
 }
 
+// SAFETY: `usb::Interface` is a transparent wrapper of `struct usb_interface`.
+// The offset is guaranteed to point to a valid device field inside `usb::Interface`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Interface<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::usb_interface, dev);
+}
+
 // SAFETY: `Interface` is a transparent wrapper of a type that doesn't depend on
 // `Interface`'s generic argument.
 kernel::impl_device_context_deref!(unsafe { Interface });