diff options
Diffstat (limited to 'rust/kernel/faux.rs')
| -rw-r--r-- | rust/kernel/faux.rs | 77 | 
1 files changed, 77 insertions, 0 deletions
| diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs new file mode 100644 index 000000000000..8a50fcd4c9bb --- /dev/null +++ b/rust/kernel/faux.rs @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only + +//! Abstractions for the faux bus. +//! +//! This module provides bindings for working with faux devices in kernel modules. +//! +//! C header: [`include/linux/device/faux.h`] + +use crate::{bindings, device, error::code::*, prelude::*}; +use core::ptr::{addr_of_mut, null, null_mut, NonNull}; + +/// The registration of a faux device. +/// +/// This type represents the registration of a [`struct faux_device`]. When an instance of this type +/// is dropped, its respective faux device will be unregistered from the system. +/// +/// # Invariants +/// +/// `self.0` always holds a valid pointer to an initialized and registered [`struct faux_device`]. +/// +/// [`struct faux_device`]: srctree/include/linux/device/faux.h +pub struct Registration(NonNull<bindings::faux_device>); + +impl Registration { +    /// Create and register a new faux device with the given name. +    #[inline] +    pub fn new(name: &CStr, parent: Option<&device::Device>) -> Result<Self> { +        // SAFETY: +        // - `name` is copied by this function into its own storage +        // - `faux_ops` is safe to leave NULL according to the C API +        // - `parent` can be either NULL or a pointer to a `struct device`, and `faux_device_create` +        //   will take a reference to `parent` using `device_add` - ensuring that it remains valid +        //   for the lifetime of the faux device. +        let dev = unsafe { +            bindings::faux_device_create( +                name.as_char_ptr(), +                parent.map_or(null_mut(), |p| p.as_raw()), +                null(), +            ) +        }; + +        // The above function will return either a valid device, or NULL on failure +        // INVARIANT: The device will remain registered until faux_device_destroy() is called, which +        // happens in our Drop implementation. +        Ok(Self(NonNull::new(dev).ok_or(ENODEV)?)) +    } + +    fn as_raw(&self) -> *mut bindings::faux_device { +        self.0.as_ptr() +    } +} + +impl AsRef<device::Device> for Registration { +    fn as_ref(&self) -> &device::Device { +        // SAFETY: The underlying `device` in `faux_device` is guaranteed by the C API to be +        // a valid initialized `device`. +        unsafe { device::Device::as_ref(addr_of_mut!((*self.as_raw()).dev)) } +    } +} + +impl Drop for Registration { +    #[inline] +    fn drop(&mut self) { +        // SAFETY: `self.0` is a valid registered faux_device via our type invariants. +        unsafe { bindings::faux_device_destroy(self.as_raw()) } +    } +} + +// SAFETY: The faux device API is thread-safe as guaranteed by the device core, as long as +// faux_device_destroy() is guaranteed to only be called once - which is guaranteed by our type not +// having Copy/Clone. +unsafe impl Send for Registration {} + +// SAFETY: The faux device API is thread-safe as guaranteed by the device core, as long as +// faux_device_destroy() is guaranteed to only be called once - which is guaranteed by our type not +// having Copy/Clone. +unsafe impl Sync for Registration {} | 
