xref: /linux/rust/kernel/faux.rs (revision fdc290ff4ab19c7e0dde36c4cd1e2771b61f6bf5)
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