xref: /linux/rust/kernel/auxiliary.rs (revision ec7714e4947909190ffb3041a03311a975350fe0)
1ce735e73SDanilo Krummrich // SPDX-License-Identifier: GPL-2.0
2ce735e73SDanilo Krummrich 
3ce735e73SDanilo Krummrich //! Abstractions for the auxiliary bus.
4ce735e73SDanilo Krummrich //!
5ce735e73SDanilo Krummrich //! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h)
6ce735e73SDanilo Krummrich 
7ce735e73SDanilo Krummrich use crate::{
80d1803d2SDanilo Krummrich     bindings, container_of, device,
9ce735e73SDanilo Krummrich     device_id::RawDeviceId,
10ce735e73SDanilo Krummrich     driver,
11ce735e73SDanilo Krummrich     error::{to_result, Result},
12ce735e73SDanilo Krummrich     prelude::*,
13ce735e73SDanilo Krummrich     str::CStr,
14ce735e73SDanilo Krummrich     types::{ForeignOwnable, Opaque},
15ce735e73SDanilo Krummrich     ThisModule,
16ce735e73SDanilo Krummrich };
17ce735e73SDanilo Krummrich use core::{
18ce735e73SDanilo Krummrich     marker::PhantomData,
19ce735e73SDanilo Krummrich     ptr::{addr_of_mut, NonNull},
20ce735e73SDanilo Krummrich };
21ce735e73SDanilo Krummrich 
22ce735e73SDanilo Krummrich /// An adapter for the registration of auxiliary drivers.
23ce735e73SDanilo Krummrich pub struct Adapter<T: Driver>(T);
24ce735e73SDanilo Krummrich 
25ce735e73SDanilo Krummrich // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
26ce735e73SDanilo Krummrich // a preceding call to `register` has been successful.
27ce735e73SDanilo Krummrich unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
28ce735e73SDanilo Krummrich     type RegType = bindings::auxiliary_driver;
29ce735e73SDanilo Krummrich 
register( adrv: &Opaque<Self::RegType>, name: &'static CStr, module: &'static ThisModule, ) -> Result30ce735e73SDanilo Krummrich     unsafe fn register(
31ce735e73SDanilo Krummrich         adrv: &Opaque<Self::RegType>,
32ce735e73SDanilo Krummrich         name: &'static CStr,
33ce735e73SDanilo Krummrich         module: &'static ThisModule,
34ce735e73SDanilo Krummrich     ) -> Result {
35ce735e73SDanilo Krummrich         // SAFETY: It's safe to set the fields of `struct auxiliary_driver` on initialization.
36ce735e73SDanilo Krummrich         unsafe {
37ce735e73SDanilo Krummrich             (*adrv.get()).name = name.as_char_ptr();
38ce735e73SDanilo Krummrich             (*adrv.get()).probe = Some(Self::probe_callback);
39ce735e73SDanilo Krummrich             (*adrv.get()).remove = Some(Self::remove_callback);
40ce735e73SDanilo Krummrich             (*adrv.get()).id_table = T::ID_TABLE.as_ptr();
41ce735e73SDanilo Krummrich         }
42ce735e73SDanilo Krummrich 
43ce735e73SDanilo Krummrich         // SAFETY: `adrv` is guaranteed to be a valid `RegType`.
44ce735e73SDanilo Krummrich         to_result(unsafe {
45ce735e73SDanilo Krummrich             bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr())
46ce735e73SDanilo Krummrich         })
47ce735e73SDanilo Krummrich     }
48ce735e73SDanilo Krummrich 
unregister(adrv: &Opaque<Self::RegType>)49ce735e73SDanilo Krummrich     unsafe fn unregister(adrv: &Opaque<Self::RegType>) {
50ce735e73SDanilo Krummrich         // SAFETY: `adrv` is guaranteed to be a valid `RegType`.
51ce735e73SDanilo Krummrich         unsafe { bindings::auxiliary_driver_unregister(adrv.get()) }
52ce735e73SDanilo Krummrich     }
53ce735e73SDanilo Krummrich }
54ce735e73SDanilo Krummrich 
55ce735e73SDanilo Krummrich impl<T: Driver + 'static> Adapter<T> {
probe_callback( adev: *mut bindings::auxiliary_device, id: *const bindings::auxiliary_device_id, ) -> kernel::ffi::c_int56ce735e73SDanilo Krummrich     extern "C" fn probe_callback(
57ce735e73SDanilo Krummrich         adev: *mut bindings::auxiliary_device,
58ce735e73SDanilo Krummrich         id: *const bindings::auxiliary_device_id,
59ce735e73SDanilo Krummrich     ) -> kernel::ffi::c_int {
60ce735e73SDanilo Krummrich         // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a
61ce735e73SDanilo Krummrich         // `struct auxiliary_device`.
62ce735e73SDanilo Krummrich         //
63ce735e73SDanilo Krummrich         // INVARIANT: `adev` is valid for the duration of `probe_callback()`.
64ce735e73SDanilo Krummrich         let adev = unsafe { &*adev.cast::<Device<device::Core>>() };
65ce735e73SDanilo Krummrich 
66ce735e73SDanilo Krummrich         // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id`
67ce735e73SDanilo Krummrich         // and does not add additional invariants, so it's safe to transmute.
68ce735e73SDanilo Krummrich         let id = unsafe { &*id.cast::<DeviceId>() };
69ce735e73SDanilo Krummrich         let info = T::ID_TABLE.info(id.index());
70ce735e73SDanilo Krummrich 
71ce735e73SDanilo Krummrich         match T::probe(adev, info) {
72ce735e73SDanilo Krummrich             Ok(data) => {
73ce735e73SDanilo Krummrich                 // Let the `struct auxiliary_device` own a reference of the driver's private data.
74ce735e73SDanilo Krummrich                 // SAFETY: By the type invariant `adev.as_raw` returns a valid pointer to a
75ce735e73SDanilo Krummrich                 // `struct auxiliary_device`.
76*ec7714e4SLinus Torvalds                 unsafe {
77*ec7714e4SLinus Torvalds                     bindings::auxiliary_set_drvdata(adev.as_raw(), data.into_foreign().cast())
78*ec7714e4SLinus Torvalds                 };
79ce735e73SDanilo Krummrich             }
80ce735e73SDanilo Krummrich             Err(err) => return Error::to_errno(err),
81ce735e73SDanilo Krummrich         }
82ce735e73SDanilo Krummrich 
83ce735e73SDanilo Krummrich         0
84ce735e73SDanilo Krummrich     }
85ce735e73SDanilo Krummrich 
remove_callback(adev: *mut bindings::auxiliary_device)86ce735e73SDanilo Krummrich     extern "C" fn remove_callback(adev: *mut bindings::auxiliary_device) {
87ce735e73SDanilo Krummrich         // SAFETY: The auxiliary bus only ever calls the remove callback with a valid pointer to a
88ce735e73SDanilo Krummrich         // `struct auxiliary_device`.
89ce735e73SDanilo Krummrich         let ptr = unsafe { bindings::auxiliary_get_drvdata(adev) };
90ce735e73SDanilo Krummrich 
91ce735e73SDanilo Krummrich         // SAFETY: `remove_callback` is only ever called after a successful call to
92ce735e73SDanilo Krummrich         // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized
93ce735e73SDanilo Krummrich         // `KBox<T>` pointer created through `KBox::into_foreign`.
94*ec7714e4SLinus Torvalds         drop(unsafe { KBox::<T>::from_foreign(ptr.cast()) });
95ce735e73SDanilo Krummrich     }
96ce735e73SDanilo Krummrich }
97ce735e73SDanilo Krummrich 
98ce735e73SDanilo Krummrich /// Declares a kernel module that exposes a single auxiliary driver.
99ce735e73SDanilo Krummrich #[macro_export]
100ce735e73SDanilo Krummrich macro_rules! module_auxiliary_driver {
101ce735e73SDanilo Krummrich     ($($f:tt)*) => {
102ce735e73SDanilo Krummrich         $crate::module_driver!(<T>, $crate::auxiliary::Adapter<T>, { $($f)* });
103ce735e73SDanilo Krummrich     };
104ce735e73SDanilo Krummrich }
105ce735e73SDanilo Krummrich 
106ce735e73SDanilo Krummrich /// Abstraction for `bindings::auxiliary_device_id`.
107ce735e73SDanilo Krummrich #[repr(transparent)]
108ce735e73SDanilo Krummrich #[derive(Clone, Copy)]
109ce735e73SDanilo Krummrich pub struct DeviceId(bindings::auxiliary_device_id);
110ce735e73SDanilo Krummrich 
111ce735e73SDanilo Krummrich impl DeviceId {
112ce735e73SDanilo Krummrich     /// Create a new [`DeviceId`] from name.
new(modname: &'static CStr, name: &'static CStr) -> Self113ce735e73SDanilo Krummrich     pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self {
114ce735e73SDanilo Krummrich         let name = name.as_bytes_with_nul();
115ce735e73SDanilo Krummrich         let modname = modname.as_bytes_with_nul();
116ce735e73SDanilo Krummrich 
117ce735e73SDanilo Krummrich         // TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for
118ce735e73SDanilo Krummrich         // `const`.
119ce735e73SDanilo Krummrich         //
120ce735e73SDanilo Krummrich         // SAFETY: FFI type is valid to be zero-initialized.
121ce735e73SDanilo Krummrich         let mut id: bindings::auxiliary_device_id = unsafe { core::mem::zeroed() };
122ce735e73SDanilo Krummrich 
123ce735e73SDanilo Krummrich         let mut i = 0;
124ce735e73SDanilo Krummrich         while i < modname.len() {
125ce735e73SDanilo Krummrich             id.name[i] = modname[i];
126ce735e73SDanilo Krummrich             i += 1;
127ce735e73SDanilo Krummrich         }
128ce735e73SDanilo Krummrich 
129ce735e73SDanilo Krummrich         // Reuse the space of the NULL terminator.
130ce735e73SDanilo Krummrich         id.name[i - 1] = b'.';
131ce735e73SDanilo Krummrich 
132ce735e73SDanilo Krummrich         let mut j = 0;
133ce735e73SDanilo Krummrich         while j < name.len() {
134ce735e73SDanilo Krummrich             id.name[i] = name[j];
135ce735e73SDanilo Krummrich             i += 1;
136ce735e73SDanilo Krummrich             j += 1;
137ce735e73SDanilo Krummrich         }
138ce735e73SDanilo Krummrich 
139ce735e73SDanilo Krummrich         Self(id)
140ce735e73SDanilo Krummrich     }
141ce735e73SDanilo Krummrich }
142ce735e73SDanilo Krummrich 
143ce735e73SDanilo Krummrich // SAFETY:
144ce735e73SDanilo Krummrich // * `DeviceId` is a `#[repr(transparent)`] wrapper of `auxiliary_device_id` and does not add
145ce735e73SDanilo Krummrich //   additional invariants, so it's safe to transmute to `RawType`.
146ce735e73SDanilo Krummrich // * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
147ce735e73SDanilo Krummrich unsafe impl RawDeviceId for DeviceId {
148ce735e73SDanilo Krummrich     type RawType = bindings::auxiliary_device_id;
149ce735e73SDanilo Krummrich 
150ce735e73SDanilo Krummrich     const DRIVER_DATA_OFFSET: usize =
151ce735e73SDanilo Krummrich         core::mem::offset_of!(bindings::auxiliary_device_id, driver_data);
152ce735e73SDanilo Krummrich 
index(&self) -> usize153ce735e73SDanilo Krummrich     fn index(&self) -> usize {
154ce735e73SDanilo Krummrich         self.0.driver_data
155ce735e73SDanilo Krummrich     }
156ce735e73SDanilo Krummrich }
157ce735e73SDanilo Krummrich 
158ce735e73SDanilo Krummrich /// IdTable type for auxiliary drivers.
159ce735e73SDanilo Krummrich pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>;
160ce735e73SDanilo Krummrich 
161ce735e73SDanilo Krummrich /// Create a auxiliary `IdTable` with its alias for modpost.
162ce735e73SDanilo Krummrich #[macro_export]
163ce735e73SDanilo Krummrich macro_rules! auxiliary_device_table {
164ce735e73SDanilo Krummrich     ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
165ce735e73SDanilo Krummrich         const $table_name: $crate::device_id::IdArray<
166ce735e73SDanilo Krummrich             $crate::auxiliary::DeviceId,
167ce735e73SDanilo Krummrich             $id_info_type,
168ce735e73SDanilo Krummrich             { $table_data.len() },
169ce735e73SDanilo Krummrich         > = $crate::device_id::IdArray::new($table_data);
170ce735e73SDanilo Krummrich 
171ce735e73SDanilo Krummrich         $crate::module_device_table!("auxiliary", $module_table_name, $table_name);
172ce735e73SDanilo Krummrich     };
173ce735e73SDanilo Krummrich }
174ce735e73SDanilo Krummrich 
175ce735e73SDanilo Krummrich /// The auxiliary driver trait.
176ce735e73SDanilo Krummrich ///
177ce735e73SDanilo Krummrich /// Drivers must implement this trait in order to get an auxiliary driver registered.
178ce735e73SDanilo Krummrich pub trait Driver {
179ce735e73SDanilo Krummrich     /// The type holding information about each device id supported by the driver.
180ce735e73SDanilo Krummrich     ///
181ce735e73SDanilo Krummrich     /// TODO: Use associated_type_defaults once stabilized:
182ce735e73SDanilo Krummrich     ///
183ce735e73SDanilo Krummrich     /// type IdInfo: 'static = ();
184ce735e73SDanilo Krummrich     type IdInfo: 'static;
185ce735e73SDanilo Krummrich 
186ce735e73SDanilo Krummrich     /// The table of device ids supported by the driver.
187ce735e73SDanilo Krummrich     const ID_TABLE: IdTable<Self::IdInfo>;
188ce735e73SDanilo Krummrich 
189ce735e73SDanilo Krummrich     /// Auxiliary driver probe.
190ce735e73SDanilo Krummrich     ///
191ce735e73SDanilo Krummrich     /// Called when an auxiliary device is matches a corresponding driver.
probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>192ce735e73SDanilo Krummrich     fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>;
193ce735e73SDanilo Krummrich }
194ce735e73SDanilo Krummrich 
195ce735e73SDanilo Krummrich /// The auxiliary device representation.
196ce735e73SDanilo Krummrich ///
197ce735e73SDanilo Krummrich /// This structure represents the Rust abstraction for a C `struct auxiliary_device`. The
198ce735e73SDanilo Krummrich /// implementation abstracts the usage of an already existing C `struct auxiliary_device` within
199ce735e73SDanilo Krummrich /// Rust code that we get passed from the C side.
200ce735e73SDanilo Krummrich ///
201ce735e73SDanilo Krummrich /// # Invariants
202ce735e73SDanilo Krummrich ///
203ce735e73SDanilo Krummrich /// A [`Device`] instance represents a valid `struct auxiliary_device` created by the C portion of
204ce735e73SDanilo Krummrich /// the kernel.
205ce735e73SDanilo Krummrich #[repr(transparent)]
206ce735e73SDanilo Krummrich pub struct Device<Ctx: device::DeviceContext = device::Normal>(
207ce735e73SDanilo Krummrich     Opaque<bindings::auxiliary_device>,
208ce735e73SDanilo Krummrich     PhantomData<Ctx>,
209ce735e73SDanilo Krummrich );
210ce735e73SDanilo Krummrich 
211ce735e73SDanilo Krummrich impl<Ctx: device::DeviceContext> Device<Ctx> {
as_raw(&self) -> *mut bindings::auxiliary_device212ce735e73SDanilo Krummrich     fn as_raw(&self) -> *mut bindings::auxiliary_device {
213ce735e73SDanilo Krummrich         self.0.get()
214ce735e73SDanilo Krummrich     }
215ce735e73SDanilo Krummrich 
216ce735e73SDanilo Krummrich     /// Returns the auxiliary device' id.
id(&self) -> u32217ce735e73SDanilo Krummrich     pub fn id(&self) -> u32 {
218ce735e73SDanilo Krummrich         // SAFETY: By the type invariant `self.as_raw()` is a valid pointer to a
219ce735e73SDanilo Krummrich         // `struct auxiliary_device`.
220ce735e73SDanilo Krummrich         unsafe { (*self.as_raw()).id }
221ce735e73SDanilo Krummrich     }
222ce735e73SDanilo Krummrich 
223ce735e73SDanilo Krummrich     /// Returns a reference to the parent [`device::Device`], if any.
parent(&self) -> Option<&device::Device>224ce735e73SDanilo Krummrich     pub fn parent(&self) -> Option<&device::Device> {
225ce735e73SDanilo Krummrich         let ptr: *const Self = self;
226ce735e73SDanilo Krummrich         // CAST: `Device<Ctx: DeviceContext>` types are transparent to each other.
227ce735e73SDanilo Krummrich         let ptr: *const Device = ptr.cast();
228ce735e73SDanilo Krummrich         // SAFETY: `ptr` was derived from `&self`.
229ce735e73SDanilo Krummrich         let this = unsafe { &*ptr };
230ce735e73SDanilo Krummrich 
231ce735e73SDanilo Krummrich         this.as_ref().parent()
232ce735e73SDanilo Krummrich     }
233ce735e73SDanilo Krummrich }
234ce735e73SDanilo Krummrich 
2350d1803d2SDanilo Krummrich impl Device {
release(dev: *mut bindings::device)2360d1803d2SDanilo Krummrich     extern "C" fn release(dev: *mut bindings::device) {
2370d1803d2SDanilo Krummrich         // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device`
2380d1803d2SDanilo Krummrich         // embedded in `struct auxiliary_device`.
239*ec7714e4SLinus Torvalds         let adev = unsafe { container_of!(dev, bindings::auxiliary_device, dev) };
2400d1803d2SDanilo Krummrich 
2410d1803d2SDanilo Krummrich         // SAFETY: `adev` points to the memory that has been allocated in `Registration::new`, via
2420d1803d2SDanilo Krummrich         // `KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)`.
2430d1803d2SDanilo Krummrich         let _ = unsafe { KBox::<Opaque<bindings::auxiliary_device>>::from_raw(adev.cast()) };
2440d1803d2SDanilo Krummrich     }
2450d1803d2SDanilo Krummrich }
2460d1803d2SDanilo Krummrich 
247ce735e73SDanilo Krummrich // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
248ce735e73SDanilo Krummrich // argument.
249ce735e73SDanilo Krummrich kernel::impl_device_context_deref!(unsafe { Device });
250ce735e73SDanilo Krummrich kernel::impl_device_context_into_aref!(Device);
251ce735e73SDanilo Krummrich 
252ce735e73SDanilo Krummrich // SAFETY: Instances of `Device` are always reference-counted.
253ce735e73SDanilo Krummrich unsafe impl crate::types::AlwaysRefCounted for Device {
inc_ref(&self)254ce735e73SDanilo Krummrich     fn inc_ref(&self) {
255ce735e73SDanilo Krummrich         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
256ce735e73SDanilo Krummrich         unsafe { bindings::get_device(self.as_ref().as_raw()) };
257ce735e73SDanilo Krummrich     }
258ce735e73SDanilo Krummrich 
dec_ref(obj: NonNull<Self>)259ce735e73SDanilo Krummrich     unsafe fn dec_ref(obj: NonNull<Self>) {
260ce735e73SDanilo Krummrich         // CAST: `Self` a transparent wrapper of `bindings::auxiliary_device`.
261ce735e73SDanilo Krummrich         let adev: *mut bindings::auxiliary_device = obj.cast().as_ptr();
262ce735e73SDanilo Krummrich 
263ce735e73SDanilo Krummrich         // SAFETY: By the type invariant of `Self`, `adev` is a pointer to a valid
264ce735e73SDanilo Krummrich         // `struct auxiliary_device`.
265ce735e73SDanilo Krummrich         let dev = unsafe { addr_of_mut!((*adev).dev) };
266ce735e73SDanilo Krummrich 
267ce735e73SDanilo Krummrich         // SAFETY: The safety requirements guarantee that the refcount is non-zero.
268ce735e73SDanilo Krummrich         unsafe { bindings::put_device(dev) }
269ce735e73SDanilo Krummrich     }
270ce735e73SDanilo Krummrich }
271ce735e73SDanilo Krummrich 
272ce735e73SDanilo Krummrich impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
as_ref(&self) -> &device::Device<Ctx>273ce735e73SDanilo Krummrich     fn as_ref(&self) -> &device::Device<Ctx> {
274ce735e73SDanilo Krummrich         // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
275ce735e73SDanilo Krummrich         // `struct auxiliary_device`.
276ce735e73SDanilo Krummrich         let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) };
277ce735e73SDanilo Krummrich 
278ce735e73SDanilo Krummrich         // SAFETY: `dev` points to a valid `struct device`.
279ce735e73SDanilo Krummrich         unsafe { device::Device::as_ref(dev) }
280ce735e73SDanilo Krummrich     }
281ce735e73SDanilo Krummrich }
282ce735e73SDanilo Krummrich 
283ce735e73SDanilo Krummrich // SAFETY: A `Device` is always reference-counted and can be released from any thread.
284ce735e73SDanilo Krummrich unsafe impl Send for Device {}
285ce735e73SDanilo Krummrich 
286ce735e73SDanilo Krummrich // SAFETY: `Device` can be shared among threads because all methods of `Device`
287ce735e73SDanilo Krummrich // (i.e. `Device<Normal>) are thread safe.
288ce735e73SDanilo Krummrich unsafe impl Sync for Device {}
2890d1803d2SDanilo Krummrich 
2900d1803d2SDanilo Krummrich /// The registration of an auxiliary device.
2910d1803d2SDanilo Krummrich ///
2920d1803d2SDanilo Krummrich /// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this
2930d1803d2SDanilo Krummrich /// type is dropped, its respective auxiliary device will be unregistered from the system.
2940d1803d2SDanilo Krummrich ///
2950d1803d2SDanilo Krummrich /// # Invariants
2960d1803d2SDanilo Krummrich ///
2970d1803d2SDanilo Krummrich /// `self.0` always holds a valid pointer to an initialized and registered
2980d1803d2SDanilo Krummrich /// [`struct auxiliary_device`].
2990d1803d2SDanilo Krummrich pub struct Registration(NonNull<bindings::auxiliary_device>);
3000d1803d2SDanilo Krummrich 
3010d1803d2SDanilo Krummrich impl Registration {
3020d1803d2SDanilo Krummrich     /// Create and register a new auxiliary device.
new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self>3030d1803d2SDanilo Krummrich     pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self> {
3040d1803d2SDanilo Krummrich         let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?;
3050d1803d2SDanilo Krummrich         let adev = boxed.get();
3060d1803d2SDanilo Krummrich 
3070d1803d2SDanilo Krummrich         // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization.
3080d1803d2SDanilo Krummrich         unsafe {
3090d1803d2SDanilo Krummrich             (*adev).dev.parent = parent.as_raw();
3100d1803d2SDanilo Krummrich             (*adev).dev.release = Some(Device::release);
3110d1803d2SDanilo Krummrich             (*adev).name = name.as_char_ptr();
3120d1803d2SDanilo Krummrich             (*adev).id = id;
3130d1803d2SDanilo Krummrich         }
3140d1803d2SDanilo Krummrich 
3150d1803d2SDanilo Krummrich         // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`,
3160d1803d2SDanilo Krummrich         // which has not been initialized yet.
3170d1803d2SDanilo Krummrich         unsafe { bindings::auxiliary_device_init(adev) };
3180d1803d2SDanilo Krummrich 
3190d1803d2SDanilo Krummrich         // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed
3200d1803d2SDanilo Krummrich         // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped.
3210d1803d2SDanilo Krummrich         let _ = KBox::into_raw(boxed);
3220d1803d2SDanilo Krummrich 
3230d1803d2SDanilo Krummrich         // SAFETY:
3240d1803d2SDanilo Krummrich         // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has
3250d1803d2SDanilo Krummrich         //   been initialialized,
3260d1803d2SDanilo Krummrich         // - `modname.as_char_ptr()` is a NULL terminated string.
3270d1803d2SDanilo Krummrich         let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) };
3280d1803d2SDanilo Krummrich         if ret != 0 {
3290d1803d2SDanilo Krummrich             // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`,
3300d1803d2SDanilo Krummrich             // which has been initialialized.
3310d1803d2SDanilo Krummrich             unsafe { bindings::auxiliary_device_uninit(adev) };
3320d1803d2SDanilo Krummrich 
3330d1803d2SDanilo Krummrich             return Err(Error::from_errno(ret));
3340d1803d2SDanilo Krummrich         }
3350d1803d2SDanilo Krummrich 
3360d1803d2SDanilo Krummrich         // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully.
3370d1803d2SDanilo Krummrich         //
3380d1803d2SDanilo Krummrich         // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called,
3390d1803d2SDanilo Krummrich         // which happens in `Self::drop()`.
3400d1803d2SDanilo Krummrich         Ok(Self(unsafe { NonNull::new_unchecked(adev) }))
3410d1803d2SDanilo Krummrich     }
3420d1803d2SDanilo Krummrich }
3430d1803d2SDanilo Krummrich 
3440d1803d2SDanilo Krummrich impl Drop for Registration {
drop(&mut self)3450d1803d2SDanilo Krummrich     fn drop(&mut self) {
3460d1803d2SDanilo Krummrich         // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered
3470d1803d2SDanilo Krummrich         // `struct auxiliary_device`.
3480d1803d2SDanilo Krummrich         unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) };
3490d1803d2SDanilo Krummrich 
3500d1803d2SDanilo Krummrich         // This drops the reference we acquired through `auxiliary_device_init()`.
3510d1803d2SDanilo Krummrich         //
3520d1803d2SDanilo Krummrich         // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered
3530d1803d2SDanilo Krummrich         // `struct auxiliary_device`.
3540d1803d2SDanilo Krummrich         unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) };
3550d1803d2SDanilo Krummrich     }
3560d1803d2SDanilo Krummrich }
3570d1803d2SDanilo Krummrich 
3580d1803d2SDanilo Krummrich // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.
3590d1803d2SDanilo Krummrich unsafe impl Send for Registration {}
3600d1803d2SDanilo Krummrich 
3610d1803d2SDanilo Krummrich // SAFETY: `Registration` does not expose any methods or fields that need synchronization.
3620d1803d2SDanilo Krummrich unsafe impl Sync for Registration {}
363