Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: auxiliary: add auxiliary registration

Implement the `auxiliary::Registration` type, which provides an API to
create and register new auxiliary devices in the system.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20250414131934.28418-5-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+87 -1
+87 -1
rust/kernel/auxiliary.rs
··· 5 5 //! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) 6 6 7 7 use crate::{ 8 - bindings, device, 8 + bindings, container_of, device, 9 9 device_id::RawDeviceId, 10 10 driver, 11 11 error::{to_result, Result}, ··· 230 230 } 231 231 } 232 232 233 + impl Device { 234 + extern "C" fn release(dev: *mut bindings::device) { 235 + // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` 236 + // embedded in `struct auxiliary_device`. 237 + let adev = unsafe { container_of!(dev, bindings::auxiliary_device, dev) }.cast_mut(); 238 + 239 + // SAFETY: `adev` points to the memory that has been allocated in `Registration::new`, via 240 + // `KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)`. 241 + let _ = unsafe { KBox::<Opaque<bindings::auxiliary_device>>::from_raw(adev.cast()) }; 242 + } 243 + } 244 + 233 245 // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 234 246 // argument. 235 247 kernel::impl_device_context_deref!(unsafe { Device }); ··· 284 272 // SAFETY: `Device` can be shared among threads because all methods of `Device` 285 273 // (i.e. `Device<Normal>) are thread safe. 286 274 unsafe impl Sync for Device {} 275 + 276 + /// The registration of an auxiliary device. 277 + /// 278 + /// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this 279 + /// type is dropped, its respective auxiliary device will be unregistered from the system. 280 + /// 281 + /// # Invariants 282 + /// 283 + /// `self.0` always holds a valid pointer to an initialized and registered 284 + /// [`struct auxiliary_device`]. 285 + pub struct Registration(NonNull<bindings::auxiliary_device>); 286 + 287 + impl Registration { 288 + /// Create and register a new auxiliary device. 289 + pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self> { 290 + let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; 291 + let adev = boxed.get(); 292 + 293 + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. 294 + unsafe { 295 + (*adev).dev.parent = parent.as_raw(); 296 + (*adev).dev.release = Some(Device::release); 297 + (*adev).name = name.as_char_ptr(); 298 + (*adev).id = id; 299 + } 300 + 301 + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, 302 + // which has not been initialized yet. 303 + unsafe { bindings::auxiliary_device_init(adev) }; 304 + 305 + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed 306 + // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped. 307 + let _ = KBox::into_raw(boxed); 308 + 309 + // SAFETY: 310 + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has 311 + // been initialialized, 312 + // - `modname.as_char_ptr()` is a NULL terminated string. 313 + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; 314 + if ret != 0 { 315 + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, 316 + // which has been initialialized. 317 + unsafe { bindings::auxiliary_device_uninit(adev) }; 318 + 319 + return Err(Error::from_errno(ret)); 320 + } 321 + 322 + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully. 323 + // 324 + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called, 325 + // which happens in `Self::drop()`. 326 + Ok(Self(unsafe { NonNull::new_unchecked(adev) })) 327 + } 328 + } 329 + 330 + impl Drop for Registration { 331 + fn drop(&mut self) { 332 + // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered 333 + // `struct auxiliary_device`. 334 + unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; 335 + 336 + // This drops the reference we acquired through `auxiliary_device_init()`. 337 + // 338 + // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered 339 + // `struct auxiliary_device`. 340 + unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; 341 + } 342 + } 343 + 344 + // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. 345 + unsafe impl Send for Registration {} 346 + 347 + // SAFETY: `Registration` does not expose any methods or fields that need synchronization. 348 + unsafe impl Sync for Registration {}