kernel/faux.rs
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
9use crate::{
10 bindings,
11 device,
12 prelude::*,
13 types::Opaque, //
14};
15use 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)]
33pub struct Device<Ctx: device::DeviceContext = device::Normal>(
34 Opaque<bindings::faux_device>,
35 PhantomData<Ctx>,
36);
37
38impl<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
54impl<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`.
65unsafe 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
80pub struct Registration(NonNull<bindings::faux_device>);
81
82impl 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
111impl 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
127impl 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.
138unsafe 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.
143unsafe impl Sync for Registration {}