| // 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 {} |