// 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`](srctree/include/linux/device/faux.h) use crate::{ bindings, device, prelude::*, types::Opaque, // }; use core::{ marker::PhantomData, ptr::{ null, null_mut, NonNull, // }, }; /// A faux device. /// /// A faux device is a virtual device backed by the faux bus, primarily used for scenarios where a /// real hardware device is not available or for testing. /// /// # Invariants /// /// The underlying `struct faux_device` is valid. #[repr(transparent)] pub struct Device( Opaque, PhantomData, ); impl Device { #[inline] fn as_raw(&self) -> *mut bindings::faux_device { self.0.get() } /// # Safety /// /// `ptr` must be a valid pointer to a `struct faux_device`. #[inline] unsafe fn from_raw<'a>(ptr: *mut bindings::faux_device) -> &'a Self { // SAFETY: `Device` is a transparent wrapper of `Opaque`. unsafe { &*ptr.cast() } } } impl AsRef> for Device { #[inline] fn as_ref(&self) -> &device::Device { // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid // `struct faux_device`. `dev` points to a valid `struct device`. unsafe { device::Device::from_raw(&raw mut (*self.as_raw()).dev) } } } // SAFETY: `faux::Device` is a transparent wrapper of `struct faux_device`. // The offset is guaranteed to point to a valid device field inside `faux::Device`. unsafe impl device::AsBusDevice for Device { const OFFSET: usize = core::mem::offset_of!(bindings::faux_device, dev); } /// 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`]. /// - This object is proof that the object described by this `Registration` is bound to a device. /// /// [`struct faux_device`]: srctree/include/linux/device/faux.h pub struct Registration(NonNull); impl Registration { /// Create and register a new faux device with the given name. #[inline] pub fn new(name: &CStr, parent: Option<&device::Device>) -> Result { // 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> for Registration { #[inline] fn as_ref(&self) -> &Device { // SAFETY: // - The underlying `struct faux_device` is guaranteed by the C API to be a valid // initialized `device`. // - `faux_match()` always returns 1, and probe runs synchronously // (PROBE_FORCE_SYNCHRONOUS). // - `suppress_bind_attrs = true` on faux_driver prevents userspace-triggered unbind via // sysfs. // - `mem::forget(Registration)` is not a problem; if the `Registration` is leaked, the faux // device stays bound forever. unsafe { Device::from_raw(self.as_raw()) } } } 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 {}