diff options
Diffstat (limited to 'rust/kernel/devres.rs')
| -rw-r--r-- | rust/kernel/devres.rs | 56 | 
1 files changed, 46 insertions, 10 deletions
| diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index ddb1ce4a78d9..0f79a2ec9474 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -8,7 +8,7 @@  use crate::{      alloc::Flags,      bindings, -    device::Device, +    device::{Bound, Device},      error::{Error, Result},      ffi::c_void,      prelude::*, @@ -45,7 +45,7 @@ struct DevresInner<T> {  /// # Example  ///  /// ```no_run -/// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::{Io, IoRaw}}; +/// # use kernel::{bindings, c_str, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}};  /// # use core::ops::Deref;  ///  /// // See also [`pci::Bar`] for a real example. @@ -83,13 +83,10 @@ struct DevresInner<T> {  ///         unsafe { Io::from_raw(&self.0) }  ///    }  /// } -/// # fn no_run() -> Result<(), Error> { -/// # // SAFETY: Invalid usage; just for the example to get an `ARef<Device>` instance. -/// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) }; -/// +/// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> {  /// // SAFETY: Invalid usage for example purposes.  /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; -/// let devres = Devres::new(&dev, iomem, GFP_KERNEL)?; +/// let devres = Devres::new(dev, iomem, GFP_KERNEL)?;  ///  /// let res = devres.try_access().ok_or(ENXIO)?;  /// res.write8(0x42, 0x0); @@ -99,7 +96,7 @@ struct DevresInner<T> {  pub struct Devres<T>(Arc<DevresInner<T>>);  impl<T> DevresInner<T> { -    fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> { +    fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {          let inner = Arc::pin_init(              pin_init!( DevresInner {                  dev: dev.into(), @@ -171,7 +168,7 @@ impl<T> DevresInner<T> {  impl<T> Devres<T> {      /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the      /// returned `Devres` instance' `data` will be revoked once the device is detached. -    pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> { +    pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self> {          let inner = DevresInner::new(dev, data, flags)?;          Ok(Devres(inner)) @@ -179,11 +176,50 @@ impl<T> Devres<T> {      /// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data`      /// is owned by devres and will be revoked / dropped, once the device is detached. -    pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result { +    pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result {          let _ = DevresInner::new(dev, data, flags)?;          Ok(())      } + +    /// Obtain `&'a T`, bypassing the [`Revocable`]. +    /// +    /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting +    /// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with. +    /// +    /// # Errors +    /// +    /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance +    /// has been created with. +    /// +    /// # Example +    /// +    /// ```no_run +    /// # #![cfg(CONFIG_PCI)] +    /// # use kernel::{device::Core, devres::Devres, pci}; +    /// +    /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result { +    ///     let bar = devres.access(dev.as_ref())?; +    /// +    ///     let _ = bar.read32(0x0); +    /// +    ///     // might_sleep() +    /// +    ///     bar.write32(0x42, 0x0); +    /// +    ///     Ok(()) +    /// } +    /// ``` +    pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> { +        if self.0.dev.as_raw() != dev.as_raw() { +            return Err(EINVAL); +        } + +        // SAFETY: `dev` being the same device as the device this `Devres` has been created for +        // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as +        // long as `dev` lives; `dev` lives at least as long as `self`. +        Ok(unsafe { self.deref().access() }) +    }  }  impl<T> Deref for Devres<T> { | 
