|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.). |
| 4 | +//! |
| 5 | +//! Each bus / subsystem is expected to implement [`RegistrationOps`], which allows drivers to |
| 6 | +//! register using the [`Registration`] class. |
| 7 | +
|
| 8 | +use crate::error::{Error, Result}; |
| 9 | +use crate::{init::PinInit, str::CStr, try_pin_init, types::Opaque, ThisModule}; |
| 10 | +use core::pin::Pin; |
| 11 | +use macros::{pin_data, pinned_drop}; |
| 12 | + |
| 13 | +/// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, |
| 14 | +/// Amba, etc.) to privide the corresponding subsystem specific implementation to register / |
| 15 | +/// unregister a driver of the particular type (`RegType`). |
| 16 | +/// |
| 17 | +/// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call |
| 18 | +/// `bindings::__pci_register_driver` from `RegistrationOps::register` and |
| 19 | +/// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. |
| 20 | +pub trait RegistrationOps { |
| 21 | + /// The type that holds information about the registration. This is typically a struct defined |
| 22 | + /// by the C portion of the kernel. |
| 23 | + type RegType: Default; |
| 24 | + |
| 25 | + /// Registers a driver. |
| 26 | + /// |
| 27 | + /// On success, `reg` must remain pinned and valid until the matching call to |
| 28 | + /// [`RegistrationOps::unregister`]. |
| 29 | + fn register( |
| 30 | + reg: &mut Self::RegType, |
| 31 | + name: &'static CStr, |
| 32 | + module: &'static ThisModule, |
| 33 | + ) -> Result; |
| 34 | + |
| 35 | + /// Unregisters a driver previously registered with [`RegistrationOps::register`]. |
| 36 | + fn unregister(reg: &mut Self::RegType); |
| 37 | +} |
| 38 | + |
| 39 | +/// A [`Registration`] is a generic type that represents the registration of some driver type (e.g. |
| 40 | +/// `bindings::pci_driver`). Therefore a [`Registration`] must be initialized with a type that |
| 41 | +/// implements the [`RegistrationOps`] trait, such that the generic `T::register` and `T::unregister` |
| 42 | +/// calls result in the subsystem specific registration calls. |
| 43 | +/// |
| 44 | +///Once the `Registration` structure is dropped, the driver is unregistered. |
| 45 | +#[pin_data(PinnedDrop)] |
| 46 | +pub struct Registration<T: RegistrationOps> { |
| 47 | + #[pin] |
| 48 | + reg: Opaque<T::RegType>, |
| 49 | +} |
| 50 | + |
| 51 | +// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to |
| 52 | +// share references to it with multiple threads as nothing can be done. |
| 53 | +unsafe impl<T: RegistrationOps> Sync for Registration<T> {} |
| 54 | + |
| 55 | +// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from |
| 56 | +// any thread, so `Registration` is `Send`. |
| 57 | +unsafe impl<T: RegistrationOps> Send for Registration<T> {} |
| 58 | + |
| 59 | +impl<T: RegistrationOps> Registration<T> { |
| 60 | + /// Creates a new instance of the registration object. |
| 61 | + pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { |
| 62 | + try_pin_init!(Self { |
| 63 | + reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { |
| 64 | + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. |
| 65 | + unsafe { ptr.write(T::RegType::default()) }; |
| 66 | + |
| 67 | + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has |
| 68 | + // just been initialised above, so it's also valid for read. |
| 69 | + let drv = unsafe { &mut *ptr }; |
| 70 | + |
| 71 | + T::register(drv, name, module) |
| 72 | + }), |
| 73 | + }) |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +#[pinned_drop] |
| 78 | +impl<T: RegistrationOps> PinnedDrop for Registration<T> { |
| 79 | + fn drop(self: Pin<&mut Self>) { |
| 80 | + // SAFETY: The existance of the `Registration` guarantees that `self.reg.get()` is properly |
| 81 | + // aligned and points to a valid value. |
| 82 | + let drv = unsafe { &mut *self.reg.get() }; |
| 83 | + |
| 84 | + T::unregister(drv); |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | +/// A kernel module that only registers the given driver on init. |
| 89 | +/// |
| 90 | +/// This is a helper struct to make it easier to define single-functionality modules, in this case, |
| 91 | +/// modules that offer a single driver. |
| 92 | +#[pin_data] |
| 93 | +pub struct Module<T: RegistrationOps> { |
| 94 | + #[pin] |
| 95 | + _driver: Registration<T>, |
| 96 | +} |
| 97 | + |
| 98 | +impl<T: RegistrationOps + Sync + Send> crate::InPlaceModule for Module<T> { |
| 99 | + fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { |
| 100 | + try_pin_init!(Self { |
| 101 | + _driver <- Registration::<T>::new(name, module), |
| 102 | + }) |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +/// Declares a kernel module that exposes a single driver. |
| 107 | +/// |
| 108 | +/// It is meant to be used as a helper by other subsystems so they can more easily expose their own |
| 109 | +/// macros. |
| 110 | +#[macro_export] |
| 111 | +macro_rules! module_driver { |
| 112 | + (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => { |
| 113 | + type Ops<$gen_type> = $driver_ops; |
| 114 | + type ModuleType = $crate::driver::Module<Ops<$type>>; |
| 115 | + $crate::prelude::module! { |
| 116 | + type: ModuleType, |
| 117 | + $($f)* |
| 118 | + } |
| 119 | + } |
| 120 | +} |
0 commit comments