| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | |
| 3 | //! Abstractions for the platform bus. |
| 4 | //! |
| 5 | //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) |
| 6 | |
| 7 | use crate::{ |
| 8 | bindings, container_of, device, driver, |
| 9 | error::{to_result, Result}, |
| 10 | of, |
| 11 | prelude::*, |
| 12 | str::CStr, |
| 13 | types::{ForeignOwnable, Opaque}, |
| 14 | ThisModule, |
| 15 | }; |
| 16 | |
| 17 | use core::{ |
| 18 | marker::PhantomData, |
| 19 | ptr::{addr_of_mut, NonNull}, |
| 20 | }; |
| 21 | |
| 22 | /// An adapter for the registration of platform drivers. |
| 23 | pub struct Adapter<T: Driver>(T); |
| 24 | |
| 25 | // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if |
| 26 | // a preceding call to `register` has been successful. |
| 27 | unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { |
| 28 | type RegType = bindings::platform_driver; |
| 29 | |
| 30 | unsafe fn register( |
| 31 | pdrv: &Opaque<Self::RegType>, |
| 32 | name: &'static CStr, |
| 33 | module: &'static ThisModule, |
| 34 | ) -> Result { |
| 35 | let of_table = match T::OF_ID_TABLE { |
| 36 | Some(table) => table.as_ptr(), |
| 37 | None => core::ptr::null(), |
| 38 | }; |
| 39 | |
| 40 | // SAFETY: It's safe to set the fields of `struct platform_driver` on initialization. |
| 41 | unsafe { |
| 42 | (*pdrv.get()).driver.name = name.as_char_ptr(); |
| 43 | (*pdrv.get()).probe = Some(Self::probe_callback); |
| 44 | (*pdrv.get()).remove = Some(Self::remove_callback); |
| 45 | (*pdrv.get()).driver.of_match_table = of_table; |
| 46 | } |
| 47 | |
| 48 | // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. |
| 49 | to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) }) |
| 50 | } |
| 51 | |
| 52 | unsafe fn unregister(pdrv: &Opaque<Self::RegType>) { |
| 53 | // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. |
| 54 | unsafe { bindings::platform_driver_unregister(pdrv.get()) }; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | impl<T: Driver + 'static> Adapter<T> { |
| 59 | extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ffi::c_int { |
| 60 | // SAFETY: The platform bus only ever calls the probe callback with a valid pointer to a |
| 61 | // `struct platform_device`. |
| 62 | // |
| 63 | // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. |
| 64 | let pdev = unsafe { &*pdev.cast::<Device<device::Core>>() }; |
| 65 | |
| 66 | let info = <Self as driver::Adapter>::id_info(pdev.as_ref()); |
| 67 | match T::probe(pdev, info) { |
| 68 | Ok(data) => { |
| 69 | // Let the `struct platform_device` own a reference of the driver's private data. |
| 70 | // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a |
| 71 | // `struct platform_device`. |
| 72 | unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; |
| 73 | } |
| 74 | Err(err) => return Error::to_errno(err), |
| 75 | } |
| 76 | |
| 77 | 0 |
| 78 | } |
| 79 | |
| 80 | extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { |
| 81 | // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. |
| 82 | let ptr = unsafe { bindings::platform_get_drvdata(pdev) }.cast(); |
| 83 | |
| 84 | // SAFETY: `remove_callback` is only ever called after a successful call to |
| 85 | // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized |
| 86 | // `KBox<T>` pointer created through `KBox::into_foreign`. |
| 87 | let _ = unsafe { KBox::<T>::from_foreign(ptr) }; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | impl<T: Driver + 'static> driver::Adapter for Adapter<T> { |
| 92 | type IdInfo = T::IdInfo; |
| 93 | |
| 94 | fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { |
| 95 | T::OF_ID_TABLE |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | /// Declares a kernel module that exposes a single platform driver. |
| 100 | /// |
| 101 | /// # Examples |
| 102 | /// |
| 103 | /// ```ignore |
| 104 | /// kernel::module_platform_driver! { |
| 105 | /// type: MyDriver, |
| 106 | /// name: "Module name", |
| 107 | /// authors: ["Author name"], |
| 108 | /// description: "Description", |
| 109 | /// license: "GPL v2", |
| 110 | /// } |
| 111 | /// ``` |
| 112 | #[macro_export] |
| 113 | macro_rules! module_platform_driver { |
| 114 | ($($f:tt)*) => { |
| 115 | $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* }); |
| 116 | }; |
| 117 | } |
| 118 | |
| 119 | /// The platform driver trait. |
| 120 | /// |
| 121 | /// Drivers must implement this trait in order to get a platform driver registered. |
| 122 | /// |
| 123 | /// # Example |
| 124 | /// |
| 125 | ///``` |
| 126 | /// # use kernel::{bindings, c_str, device::Core, of, platform}; |
| 127 | /// |
| 128 | /// struct MyDriver; |
| 129 | /// |
| 130 | /// kernel::of_device_table!( |
| 131 | /// OF_TABLE, |
| 132 | /// MODULE_OF_TABLE, |
| 133 | /// <MyDriver as platform::Driver>::IdInfo, |
| 134 | /// [ |
| 135 | /// (of::DeviceId::new(c_str!("test,device")), ()) |
| 136 | /// ] |
| 137 | /// ); |
| 138 | /// |
| 139 | /// impl platform::Driver for MyDriver { |
| 140 | /// type IdInfo = (); |
| 141 | /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 142 | /// |
| 143 | /// fn probe( |
| 144 | /// _pdev: &platform::Device<Core>, |
| 145 | /// _id_info: Option<&Self::IdInfo>, |
| 146 | /// ) -> Result<Pin<KBox<Self>>> { |
| 147 | /// Err(ENODEV) |
| 148 | /// } |
| 149 | /// } |
| 150 | ///``` |
| 151 | pub trait Driver: Send { |
| 152 | /// The type holding driver private data about each device id supported by the driver. |
| 153 | // TODO: Use associated_type_defaults once stabilized: |
| 154 | // |
| 155 | // ``` |
| 156 | // type IdInfo: 'static = (); |
| 157 | // ``` |
| 158 | type IdInfo: 'static; |
| 159 | |
| 160 | /// The table of OF device ids supported by the driver. |
| 161 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>>; |
| 162 | |
| 163 | /// Platform driver probe. |
| 164 | /// |
| 165 | /// Called when a new platform device is added or discovered. |
| 166 | /// Implementers should attempt to initialize the device here. |
| 167 | fn probe(dev: &Device<device::Core>, id_info: Option<&Self::IdInfo>) |
| 168 | -> Result<Pin<KBox<Self>>>; |
| 169 | } |
| 170 | |
| 171 | /// The platform device representation. |
| 172 | /// |
| 173 | /// This structure represents the Rust abstraction for a C `struct platform_device`. The |
| 174 | /// implementation abstracts the usage of an already existing C `struct platform_device` within Rust |
| 175 | /// code that we get passed from the C side. |
| 176 | /// |
| 177 | /// # Invariants |
| 178 | /// |
| 179 | /// A [`Device`] instance represents a valid `struct platform_device` created by the C portion of |
| 180 | /// the kernel. |
| 181 | #[repr(transparent)] |
| 182 | pub struct Device<Ctx: device::DeviceContext = device::Normal>( |
| 183 | Opaque<bindings::platform_device>, |
| 184 | PhantomData<Ctx>, |
| 185 | ); |
| 186 | |
| 187 | impl<Ctx: device::DeviceContext> Device<Ctx> { |
| 188 | fn as_raw(&self) -> *mut bindings::platform_device { |
| 189 | self.0.get() |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic |
| 194 | // argument. |
| 195 | kernel::impl_device_context_deref!(unsafe { Device }); |
| 196 | kernel::impl_device_context_into_aref!(Device); |
| 197 | |
| 198 | // SAFETY: Instances of `Device` are always reference-counted. |
| 199 | unsafe impl crate::types::AlwaysRefCounted for Device { |
| 200 | fn inc_ref(&self) { |
| 201 | // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. |
| 202 | unsafe { bindings::get_device(self.as_ref().as_raw()) }; |
| 203 | } |
| 204 | |
| 205 | unsafe fn dec_ref(obj: NonNull<Self>) { |
| 206 | // SAFETY: The safety requirements guarantee that the refcount is non-zero. |
| 207 | unsafe { bindings::platform_device_put(obj.cast().as_ptr()) } |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { |
| 212 | fn as_ref(&self) -> &device::Device<Ctx> { |
| 213 | // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid |
| 214 | // `struct platform_device`. |
| 215 | let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; |
| 216 | |
| 217 | // SAFETY: `dev` points to a valid `struct device`. |
| 218 | unsafe { device::Device::as_ref(dev) } |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> { |
| 223 | type Error = kernel::error::Error; |
| 224 | |
| 225 | fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { |
| 226 | // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a |
| 227 | // `struct device`. |
| 228 | if !unsafe { bindings::dev_is_platform(dev.as_raw()) } { |
| 229 | return Err(EINVAL); |
| 230 | } |
| 231 | |
| 232 | // SAFETY: We've just verified that the bus type of `dev` equals |
| 233 | // `bindings::platform_bus_type`, hence `dev` must be embedded in a valid |
| 234 | // `struct platform_device` as guaranteed by the corresponding C code. |
| 235 | let pdev = unsafe { container_of!(dev.as_raw(), bindings::platform_device, dev) }; |
| 236 | |
| 237 | // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. |
| 238 | Ok(unsafe { &*pdev.cast() }) |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | // SAFETY: A `Device` is always reference-counted and can be released from any thread. |
| 243 | unsafe impl Send for Device {} |
| 244 | |
| 245 | // SAFETY: `Device` can be shared among threads because all methods of `Device` |
| 246 | // (i.e. `Device<Normal>) are thread safe. |
| 247 | unsafe impl Sync for Device {} |
| 248 | |