Struct Devres

Source
pub struct Devres<T>(/* private fields */);
Expand description

This abstraction is meant to be used by subsystems to containerize Device bound resources to manage their lifetime.

Device bound resources should be freed when either the resource goes out of scope or the Device is unbound respectively, depending on what happens first. In any case, it is always guaranteed that revoking the device resource is completed before the corresponding Device is unbound.

To achieve that Devres registers a devres callback on creation, which is called once the Device is unbound, revoking access to the encapsulated resource (see also Revocable).

After the Devres has been unbound it is not possible to access the encapsulated resource anymore.

Devres users should make sure to simply free the corresponding backing resource in T’s Drop implementation.

§Example


// See also [`pci::Bar`] for a real example.
struct IoMem<const SIZE: usize>(IoRaw<SIZE>);

impl<const SIZE: usize> IoMem<SIZE> {
    /// # Safety
    ///
    /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs
    /// virtual address space.
    unsafe fn new(paddr: usize) -> Result<Self>{
        // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
        // valid for `ioremap`.
        let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) };
        if addr.is_null() {
            return Err(ENOMEM);
        }

        Ok(IoMem(IoRaw::new(addr as _, SIZE)?))
    }
}

impl<const SIZE: usize> Drop for IoMem<SIZE> {
    fn drop(&mut self) {
        // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
        unsafe { bindings::iounmap(self.0.addr() as _); };
    }
}

impl<const SIZE: usize> Deref for IoMem<SIZE> {
   type Target = Io<SIZE>;

   fn deref(&self) -> &Self::Target {
        // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
        unsafe { Io::from_raw(&self.0) }
   }
}
// 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 res = devres.try_access().ok_or(ENXIO)?;
res.write8(0x42, 0x0);

Implementations§

Source§

impl<T> Devres<T>

Source

pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self>

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.

Source

pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result

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.

Source

pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T>

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

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(())
}
Source

pub fn try_access(&self) -> Option<RevocableGuard<'_, T>>

Source

pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R>

Source

pub fn try_access_with_guard<'a>(&'a self, guard: &'a Guard) -> Option<&'a T>

Trait Implementations§

Source§

impl<T> Drop for Devres<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<T> Freeze for Devres<T>

§

impl<T> !RefUnwindSafe for Devres<T>

§

impl<T> Send for Devres<T>
where T: Sync + Send,

§

impl<T> Sync for Devres<T>
where T: Sync + Send,

§

impl<T> Unpin for Devres<T>

§

impl<T> !UnwindSafe for Devres<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, E> Init<T, E> for T

Source§

unsafe fn __init(self, slot: *mut T) -> Result<(), E>

Initializes slot. Read more
Source§

fn chain<F>(self, f: F) -> ChainInit<Self, F, T, E>
where F: FnOnce(&mut T) -> Result<(), E>,

First initializes the value using self then calls the function f with the initialized value. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, E> PinInit<T, E> for T

Source§

unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>

Initializes slot. Read more
Source§

fn pin_chain<F>(self, f: F) -> ChainPinInit<Self, F, T, E>
where F: FnOnce(Pin<&mut T>) -> Result<(), E>,

First initializes the value using self then calls the function f with the initialized value. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.