// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{alloc::flags::*, prelude::*}; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. pub struct Registration { driver: Pin>>, _p: PhantomData, } impl Registration where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result { let driver = KBox::pin(UnsafeCell::new(T::RegType::default()), GFP_KERNEL)?; // SAFETY: `driver` has just been initialized; it's only freed after `Self::drop`, which // calls `T::unregister` first. unsafe { T::register(driver.get(), name, module) }?; Ok(Self { driver, _p: PhantomData::, }) } } impl Drop for Registration where T: RegistrationOps, { fn drop(&mut self) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl Sync for Registration where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl Send for Registration where T: RegistrationOps {}