]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
rust: device: add drvdata accessors
authorDanilo Krummrich <dakr@kernel.org>
Sat, 21 Jun 2025 19:43:28 +0000 (21:43 +0200)
committerDanilo Krummrich <dakr@kernel.org>
Tue, 8 Jul 2025 22:04:33 +0000 (00:04 +0200)
Implement generic accessors for the private data of a driver bound to a
device.

Those accessors should be used by bus abstractions from their
corresponding core callbacks, such as probe(), remove(), etc.

Implementing them for device::CoreInternal guarantees that driver's can't
interfere with the logic implemented by the bus abstraction.

Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://lore.kernel.org/r/20250621195118.124245-3-dakr@kernel.org
[ Improve safety comment as proposed by Benno. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
rust/helpers/device.c
rust/kernel/device.rs

index 502fef7e9ae87a107c61f203a3ee41309ced61aa..9a4316bafedfbc4015446ce1945f1bf1ae7face1 100644 (file)
@@ -15,3 +15,13 @@ int rust_helper_devm_add_action_or_reset(struct device *dev,
 {
        return devm_add_action_or_reset(dev, action, data);
 }
+
+void *rust_helper_dev_get_drvdata(const struct device *dev)
+{
+       return dev_get_drvdata(dev);
+}
+
+void rust_helper_dev_set_drvdata(struct device *dev, void *data)
+{
+       dev_set_drvdata(dev, data);
+}
index 6b8acee4a378ec3ed9b344cf58a03884f4d6f17a..d527ceef829ea7b11e72bd34a631711e7c64f565 100644 (file)
@@ -6,7 +6,7 @@
 
 use crate::{
     bindings,
-    types::{ARef, Opaque},
+    types::{ARef, ForeignOwnable, Opaque},
 };
 use core::{fmt, marker::PhantomData, ptr};
 
@@ -62,6 +62,53 @@ impl Device {
     }
 }
 
+impl Device<CoreInternal> {
+    /// Store a pointer to the bound driver's private data.
+    pub fn set_drvdata(&self, data: impl ForeignOwnable) {
+        // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`.
+        unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreign().cast()) }
+    }
+
+    /// Take ownership of the private data stored in this [`Device`].
+    ///
+    /// # Safety
+    ///
+    /// - Must only be called once after a preceding call to [`Device::set_drvdata`].
+    /// - The type `T` must match the type of the `ForeignOwnable` previously stored by
+    ///   [`Device::set_drvdata`].
+    pub unsafe fn drvdata_obtain<T: ForeignOwnable>(&self) -> 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()) };
+
+        // SAFETY:
+        // - By the safety requirements of this function, `ptr` comes from a previous call to
+        //   `into_foreign()`.
+        // - `dev_get_drvdata()` guarantees to return the same pointer given to `dev_set_drvdata()`
+        //   in `into_foreign()`.
+        unsafe { T::from_foreign(ptr.cast()) }
+    }
+
+    /// 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
+    ///   [`Device::drvdata_obtain`].
+    /// - The type `T` must match the type of the `ForeignOwnable` previously stored by
+    ///   [`Device::set_drvdata`].
+    pub unsafe fn drvdata_borrow<T: ForeignOwnable>(&self) -> T::Borrowed<'_> {
+        // 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()) };
+
+        // SAFETY:
+        // - By the safety requirements of this function, `ptr` comes from a previous call to
+        //   `into_foreign()`.
+        // - `dev_get_drvdata()` guarantees to return the same pointer given to `dev_set_drvdata()`
+        //   in `into_foreign()`.
+        unsafe { T::borrow(ptr.cast()) }
+    }
+}
+
 impl<Ctx: DeviceContext> Device<Ctx> {
     /// Obtain the raw `struct device *`.
     pub(crate) fn as_raw(&self) -> *mut bindings::device {