1 // SPDX-License-Identifier: GPL-2.0-only 2 3 //! Abstractions for the faux bus. 4 //! 5 //! This module provides bindings for working with faux devices in kernel modules. 6 //! 7 //! C header: [`include/linux/device/faux.h`](srctree/include/linux/device/faux.h) 8 9 use crate::{ 10 bindings, 11 device, 12 prelude::*, 13 types::Opaque, // 14 }; 15 use core::{ 16 marker::PhantomData, 17 ptr::{ 18 null, 19 null_mut, 20 NonNull, // 21 }, 22 }; 23 24 /// A faux device. 25 /// 26 /// A faux device is a virtual device backed by the faux bus, primarily used for scenarios where a 27 /// real hardware device is not available or for testing. 28 /// 29 /// # Invariants 30 /// 31 /// The underlying `struct faux_device` is valid. 32 #[repr(transparent)] 33 pub struct Device<Ctx: device::DeviceContext = device::Normal>( 34 Opaque<bindings::faux_device>, 35 PhantomData<Ctx>, 36 ); 37 38 impl<Ctx: device::DeviceContext> Device<Ctx> { 39 #[inline] 40 fn as_raw(&self) -> *mut bindings::faux_device { 41 self.0.get() 42 } 43 44 /// # Safety 45 /// 46 /// `ptr` must be a valid pointer to a `struct faux_device`. 47 #[inline] 48 unsafe fn from_raw<'a>(ptr: *mut bindings::faux_device) -> &'a Self { 49 // SAFETY: `Device` is a transparent wrapper of `Opaque<bindings::faux_device>`. 50 unsafe { &*ptr.cast() } 51 } 52 } 53 54 impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { 55 #[inline] 56 fn as_ref(&self) -> &device::Device<Ctx> { 57 // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 58 // `struct faux_device`. `dev` points to a valid `struct device`. 59 unsafe { device::Device::from_raw(&raw mut (*self.as_raw()).dev) } 60 } 61 } 62 63 // SAFETY: `faux::Device` is a transparent wrapper of `struct faux_device`. 64 // The offset is guaranteed to point to a valid device field inside `faux::Device`. 65 unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> { 66 const OFFSET: usize = core::mem::offset_of!(bindings::faux_device, dev); 67 } 68 69 /// The registration of a faux device. 70 /// 71 /// This type represents the registration of a [`struct faux_device`]. When an instance of this type 72 /// is dropped, its respective faux device will be unregistered from the system. 73 /// 74 /// # Invariants 75 /// 76 /// - `self.0` always holds a valid pointer to an initialized and registered [`struct faux_device`]. 77 /// - This object is proof that the object described by this `Registration` is bound to a device. 78 /// 79 /// [`struct faux_device`]: srctree/include/linux/device/faux.h 80 pub struct Registration(NonNull<bindings::faux_device>); 81 82 impl Registration { 83 /// Create and register a new faux device with the given name. 84 #[inline] 85 pub fn new(name: &CStr, parent: Option<&device::Device>) -> Result<Self> { 86 // SAFETY: 87 // - `name` is copied by this function into its own storage 88 // - `faux_ops` is safe to leave NULL according to the C API 89 // - `parent` can be either NULL or a pointer to a `struct device`, and `faux_device_create` 90 // will take a reference to `parent` using `device_add` - ensuring that it remains valid 91 // for the lifetime of the faux device. 92 let dev = unsafe { 93 bindings::faux_device_create( 94 name.as_char_ptr(), 95 parent.map_or(null_mut(), |p| p.as_raw()), 96 null(), 97 ) 98 }; 99 100 // The above function will return either a valid device, or NULL on failure 101 // INVARIANT: The device will remain registered until faux_device_destroy() is called, which 102 // happens in our Drop implementation. 103 Ok(Self(NonNull::new(dev).ok_or(ENODEV)?)) 104 } 105 106 fn as_raw(&self) -> *mut bindings::faux_device { 107 self.0.as_ptr() 108 } 109 } 110 111 impl AsRef<Device<device::Bound>> for Registration { 112 #[inline] 113 fn as_ref(&self) -> &Device<device::Bound> { 114 // SAFETY: 115 // - The underlying `struct faux_device` is guaranteed by the C API to be a valid 116 // initialized `device`. 117 // - `faux_match()` always returns 1, and probe runs synchronously 118 // (PROBE_FORCE_SYNCHRONOUS). 119 // - `suppress_bind_attrs = true` on faux_driver prevents userspace-triggered unbind via 120 // sysfs. 121 // - `mem::forget(Registration)` is not a problem; if the `Registration` is leaked, the faux 122 // device stays bound forever. 123 unsafe { Device::from_raw(self.as_raw()) } 124 } 125 } 126 127 impl Drop for Registration { 128 #[inline] 129 fn drop(&mut self) { 130 // SAFETY: `self.0` is a valid registered faux_device via our type invariants. 131 unsafe { bindings::faux_device_destroy(self.as_raw()) } 132 } 133 } 134 135 // SAFETY: The faux device API is thread-safe as guaranteed by the device core, as long as 136 // faux_device_destroy() is guaranteed to only be called once - which is guaranteed by our type not 137 // having Copy/Clone. 138 unsafe impl Send for Registration {} 139 140 // SAFETY: The faux device API is thread-safe as guaranteed by the device core, as long as 141 // faux_device_destroy() is guaranteed to only be called once - which is guaranteed by our type not 142 // having Copy/Clone. 143 unsafe impl Sync for Registration {} 144