Commit e4addc7c authored by Markus Probst's avatar Markus Probst Committed by Danilo Krummrich
Browse files

rust: Add trait to convert a device reference to a bus device reference



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: default avatarMarkus 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: default avatarDanilo Krummrich <dakr@kernel.org>
parent 13ae55e2
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
};
use core::{
    marker::PhantomData,
    mem::offset_of,
    ptr::{addr_of_mut, NonNull},
};

@@ -245,6 +246,12 @@ extern "C" fn release(dev: *mut bindings::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 });
+33 −0
Original line number Diff line number Diff line
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

use core::{
    marker::PhantomData,
    mem::offset_of,
    ptr::{
        from_ref,
        NonNull, //
@@ -476,6 +477,12 @@ fn as_raw(&self) -> *mut bindings::i2c_client {
    }
}

// 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 });
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
};
use core::{
    marker::PhantomData,
    mem::offset_of,
    ptr::{
        addr_of_mut,
        NonNull, //
@@ -443,6 +444,12 @@ pub fn set_master(&self) {
    }
}

// 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 });
+7 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

use core::{
    marker::PhantomData,
    mem::offset_of,
    ptr::{addr_of_mut, NonNull},
};

@@ -287,6 +288,12 @@ pub fn io_request_by_name(&self, name: &CStr) -> Option<IoRequest<'_>> {
    }
}

// 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,
Loading