|
| 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 [`DriverOps`], which allows drivers to register |
| 6 | +//! 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 [`DriverOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, Amba, |
| 14 | +/// etc.) to privide the corresponding subsystem specific implementation to register / unregister a |
| 15 | +/// 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 `DriverOps::register` and |
| 19 | +/// `bindings::pci_unregister_driver` from `DriverOps::unregister`. |
| 20 | +pub trait DriverOps { |
| 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 | + /// # Safety |
| 28 | + /// |
| 29 | + /// `reg` must point to valid, initialised, and writable memory. It may be modified by this |
| 30 | + /// function to hold registration state. |
| 31 | + /// |
| 32 | + /// On success, `reg` must remain pinned and valid until the matching call to |
| 33 | + /// [`DriverOps::unregister`]. |
| 34 | + fn register( |
| 35 | + reg: &mut Self::RegType, |
| 36 | + name: &'static CStr, |
| 37 | + module: &'static ThisModule, |
| 38 | + ) -> Result; |
| 39 | + |
| 40 | + /// Unregisters a driver previously registered with [`DriverOps::register`]. |
| 41 | + /// |
| 42 | + /// # Safety |
| 43 | + /// |
| 44 | + /// `reg` must point to valid writable memory, initialised by a previous successful call to |
| 45 | + /// [`DriverOps::register`]. |
| 46 | + fn unregister(reg: &mut Self::RegType); |
| 47 | +} |
| 48 | + |
| 49 | +/// A [`Registration`] is a generic type that represents the registration of some driver type (e.g. |
| 50 | +/// `bindings::pci_driver`). Therefore a [`Registration`] is initialized with some type that |
| 51 | +/// implements the [`DriverOps`] trait, such that the generic `T::register` and `T::unregister` |
| 52 | +/// calls result in the subsystem specific registration calls. |
| 53 | +/// |
| 54 | +///Once the `Registration` structure is dropped, the driver is unregistered. |
| 55 | +#[pin_data(PinnedDrop)] |
| 56 | +pub struct Registration<T: DriverOps> { |
| 57 | + #[pin] |
| 58 | + reg: Opaque<T::RegType>, |
| 59 | +} |
| 60 | + |
| 61 | +// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to |
| 62 | +// share references to it with multiple threads as nothing can be done. |
| 63 | +unsafe impl<T: DriverOps> Sync for Registration<T> {} |
| 64 | + |
| 65 | +// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from |
| 66 | +// any thread, so `Registration` is `Send`. |
| 67 | +unsafe impl<T: DriverOps> Send for Registration<T> {} |
| 68 | + |
| 69 | +impl<T: DriverOps> Registration<T> { |
| 70 | + /// Creates a new instance of the registration object. |
| 71 | + pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { |
| 72 | + try_pin_init!(Self { |
| 73 | + reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { |
| 74 | + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. |
| 75 | + unsafe { ptr.write(T::RegType::default()) }; |
| 76 | + |
| 77 | + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has |
| 78 | + // just been initialised above, so it's also valid for read. |
| 79 | + let drv = unsafe { &mut *ptr }; |
| 80 | + |
| 81 | + T::register(drv, name, module) |
| 82 | + }), |
| 83 | + }) |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +#[pinned_drop] |
| 88 | +impl<T: DriverOps> PinnedDrop for Registration<T> { |
| 89 | + fn drop(self: Pin<&mut Self>) { |
| 90 | + let drv = unsafe { &mut *self.reg.get() }; |
| 91 | + |
| 92 | + T::unregister(drv); |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +/// A kernel module that only registers the given driver on init. |
| 97 | +/// |
| 98 | +/// This is a helper struct to make it easier to define single-functionality modules, in this case, |
| 99 | +/// modules that offer a single driver. |
| 100 | +#[pin_data] |
| 101 | +pub struct Module<T: DriverOps> { |
| 102 | + #[pin] |
| 103 | + _driver: Registration<T>, |
| 104 | +} |
| 105 | + |
| 106 | +impl<T: DriverOps + Sync + Send> crate::InPlaceModule for Module<T> { |
| 107 | + fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { |
| 108 | + try_pin_init!(Self { |
| 109 | + _driver <- Registration::<T>::new(name, module), |
| 110 | + }) |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +/// Declares a kernel module that exposes a single driver. |
| 115 | +/// |
| 116 | +/// It is meant to be used as a helper by other subsystems so they can more easily expose their own |
| 117 | +/// macros. |
| 118 | +#[macro_export] |
| 119 | +macro_rules! module_driver { |
| 120 | + (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => { |
| 121 | + type Ops<$gen_type> = $driver_ops; |
| 122 | + type ModuleType = $crate::driver::Module<Ops<$type>>; |
| 123 | + $crate::prelude::module! { |
| 124 | + type: ModuleType, |
| 125 | + $($f)* |
| 126 | + } |
| 127 | + } |
| 128 | +} |
0 commit comments