|
7 | 7 |
|
8 | 8 | use crate::{str::CStr, sync::Ref, Error, KernelModule, Result, ScopeGuard, ThisModule};
|
9 | 9 | use alloc::{boxed::Box, vec::Vec};
|
10 |
| -use core::{cell::UnsafeCell, mem::MaybeUninit, ops::Deref, pin::Pin}; |
| 10 | +use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::Deref, pin::Pin}; |
11 | 11 |
|
12 | 12 | /// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
|
13 | 13 | pub trait DriverOps {
|
@@ -162,6 +162,281 @@ impl<T: DriverOps> Drop for Registration<T> {
|
162 | 162 | }
|
163 | 163 | }
|
164 | 164 |
|
| 165 | +/// Conversion from a device id to a raw device id. |
| 166 | +/// |
| 167 | +/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to |
| 168 | +/// guarantee (at compile-time) zero-termination of device id tables provided by drivers. |
| 169 | +/// |
| 170 | +/// # Safety |
| 171 | +/// |
| 172 | +/// Implementers must ensure that: |
| 173 | +/// * [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id. |
| 174 | +/// * [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so |
| 175 | +/// that buses can recover the pointer to the data. |
| 176 | +pub unsafe trait RawDeviceId { |
| 177 | + /// The raw type that holds the device id. |
| 178 | + /// |
| 179 | + /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array. |
| 180 | + type RawType: Copy; |
| 181 | + |
| 182 | + /// A zeroed-out representation of the raw device id. |
| 183 | + /// |
| 184 | + /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of |
| 185 | + /// the table. |
| 186 | + const ZERO: Self::RawType; |
| 187 | + |
| 188 | + /// Converts an id into a raw id. |
| 189 | + /// |
| 190 | + /// `offset` is the offset from the memory location where the raw device id is stored to the |
| 191 | + /// location where its associated context information is stored. Implementations must store |
| 192 | + /// this in the appropriate context/data field of the raw type. |
| 193 | + fn to_rawid(&self, offset: isize) -> Self::RawType; |
| 194 | +} |
| 195 | + |
| 196 | +/// A zero-terminated device id array, followed by context data. |
| 197 | +#[repr(C)] |
| 198 | +pub struct IdArray<T: RawDeviceId, U, const N: usize> { |
| 199 | + ids: [T::RawType; N], |
| 200 | + sentinel: T::RawType, |
| 201 | + id_infos: [Option<U>; N], |
| 202 | +} |
| 203 | + |
| 204 | +impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> { |
| 205 | + /// Creates a new instance of the array. |
| 206 | + /// |
| 207 | + /// The contents are derived from the given identifiers and context information. |
| 208 | + pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self |
| 209 | + where |
| 210 | + T: ~const RawDeviceId + Copy, |
| 211 | + { |
| 212 | + let mut array = Self { |
| 213 | + ids: [T::ZERO; N], |
| 214 | + sentinel: T::ZERO, |
| 215 | + id_infos: infos, |
| 216 | + }; |
| 217 | + let mut i = 0usize; |
| 218 | + while i < N { |
| 219 | + // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are |
| 220 | + // derived from the same allocated object. We are using a `u8` pointer, whose size 1, |
| 221 | + // so the pointers are necessarily 1-byte aligned. |
| 222 | + let offset = unsafe { |
| 223 | + (&array.id_infos[i] as *const _ as *const u8) |
| 224 | + .offset_from(&array.ids[i] as *const _ as _) |
| 225 | + }; |
| 226 | + array.ids[i] = ids[i].to_rawid(offset); |
| 227 | + i += 1; |
| 228 | + } |
| 229 | + array |
| 230 | + } |
| 231 | + |
| 232 | + /// Returns an `IdTable` backed by `self`. |
| 233 | + /// |
| 234 | + /// This is used to essentially erase the array size. |
| 235 | + pub const fn as_table(&self) -> IdTable<'_, T, U> { |
| 236 | + IdTable { |
| 237 | + first: &self.ids[0], |
| 238 | + _p: PhantomData, |
| 239 | + } |
| 240 | + } |
| 241 | +} |
| 242 | + |
| 243 | +/// A device id table. |
| 244 | +/// |
| 245 | +/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of |
| 246 | +/// type `Option<U>`. |
| 247 | +pub struct IdTable<'a, T: RawDeviceId, U> { |
| 248 | + first: &'a T::RawType, |
| 249 | + _p: PhantomData<&'a U>, |
| 250 | +} |
| 251 | + |
| 252 | +impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> { |
| 253 | + fn as_ref(&self) -> &T::RawType { |
| 254 | + self.first |
| 255 | + } |
| 256 | +} |
| 257 | + |
| 258 | +/// Counts the number of parenthesis-delimited, comma-separated items. |
| 259 | +/// |
| 260 | +/// # Examples |
| 261 | +/// |
| 262 | +/// ``` |
| 263 | +/// # use kernel::count_paren_items; |
| 264 | +/// |
| 265 | +/// assert_eq!(0, count_paren_items!()); |
| 266 | +/// assert_eq!(1, count_paren_items!((A))); |
| 267 | +/// assert_eq!(1, count_paren_items!((A),)); |
| 268 | +/// assert_eq!(2, count_paren_items!((A), (B))); |
| 269 | +/// assert_eq!(2, count_paren_items!((A), (B),)); |
| 270 | +/// assert_eq!(3, count_paren_items!((A), (B), (C))); |
| 271 | +/// assert_eq!(3, count_paren_items!((A), (B), (C),)); |
| 272 | +/// ``` |
| 273 | +#[macro_export] |
| 274 | +macro_rules! count_paren_items { |
| 275 | + (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; |
| 276 | + (($($item:tt)*)) => { 1 }; |
| 277 | + () => { 0 }; |
| 278 | +} |
| 279 | + |
| 280 | +/// Converts a comma-separated list of pairs into an array with the first element. That is, it |
| 281 | +/// discards the second element of the pair. |
| 282 | +/// |
| 283 | +/// Additionally, it automatically introduces a type if the first element is warpped in curly |
| 284 | +/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating |
| 285 | +/// the type. |
| 286 | +/// |
| 287 | +/// # Examples |
| 288 | +/// |
| 289 | +/// ``` |
| 290 | +/// # use kernel::first_item; |
| 291 | +/// |
| 292 | +/// #[derive(PartialEq, Debug)] |
| 293 | +/// struct X { |
| 294 | +/// v: u32, |
| 295 | +/// } |
| 296 | +/// |
| 297 | +/// assert_eq!([] as [X; 0], first_item!(X, )); |
| 298 | +/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y))); |
| 299 | +/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),)); |
| 300 | +/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y))); |
| 301 | +/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),)); |
| 302 | +/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y))); |
| 303 | +/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),)); |
| 304 | +/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y))); |
| 305 | +/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),)); |
| 306 | +/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], |
| 307 | +/// first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y))); |
| 308 | +/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], |
| 309 | +/// first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),)); |
| 310 | +/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], |
| 311 | +/// first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y))); |
| 312 | +/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], |
| 313 | +/// first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),)); |
| 314 | +/// ``` |
| 315 | +#[macro_export] |
| 316 | +macro_rules! first_item { |
| 317 | + ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { |
| 318 | + { |
| 319 | + type IdType = $id_type; |
| 320 | + [$(IdType{$($first)*},)*] |
| 321 | + } |
| 322 | + }; |
| 323 | + ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; |
| 324 | +} |
| 325 | + |
| 326 | +/// Converts a comma-separated list of pairs into an array with the second element. That is, it |
| 327 | +/// discards the first element of the pair. |
| 328 | +/// |
| 329 | +/// # Examples |
| 330 | +/// |
| 331 | +/// ``` |
| 332 | +/// # use kernel::second_item; |
| 333 | +/// |
| 334 | +/// assert_eq!([] as [u32; 0], second_item!()); |
| 335 | +/// assert_eq!([10u32], second_item!((X, 10u32))); |
| 336 | +/// assert_eq!([10u32], second_item!((X, 10u32),)); |
| 337 | +/// assert_eq!([10u32], second_item!(({X}, 10u32))); |
| 338 | +/// assert_eq!([10u32], second_item!(({X}, 10u32),)); |
| 339 | +/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20))); |
| 340 | +/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),)); |
| 341 | +/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20))); |
| 342 | +/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20),)); |
| 343 | +/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30))); |
| 344 | +/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),)); |
| 345 | +/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30))); |
| 346 | +/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30),)); |
| 347 | +/// ``` |
| 348 | +#[macro_export] |
| 349 | +macro_rules! second_item { |
| 350 | + ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; |
| 351 | + ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; |
| 352 | +} |
| 353 | + |
| 354 | +/// Defines a new constant [`IdArray`] with a concise syntax. |
| 355 | +/// |
| 356 | +/// It is meant to be used by buses and subsystems to create a similar macro with their device id |
| 357 | +/// type already specified, i.e., with fewer parameters to the end user. |
| 358 | +/// |
| 359 | +/// # Examples |
| 360 | +/// |
| 361 | +/// ``` |
| 362 | +/// #![feature(const_trait_impl)] |
| 363 | +/// # use kernel::{define_id_array, driver::RawDeviceId}; |
| 364 | +/// |
| 365 | +/// #[derive(Copy, Clone)] |
| 366 | +/// struct Id(u32); |
| 367 | +/// |
| 368 | +/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw |
| 369 | +/// // device id pair. |
| 370 | +/// unsafe impl const RawDeviceId for Id { |
| 371 | +/// type RawType = (u64, isize); |
| 372 | +/// const ZERO: Self::RawType = (0, 0); |
| 373 | +/// fn to_rawid(&self, offset: isize) -> Self::RawType { |
| 374 | +/// (self.0 as u64 + 1, offset) |
| 375 | +/// } |
| 376 | +/// } |
| 377 | +/// |
| 378 | +/// define_id_array!(A1, Id, (), []); |
| 379 | +/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]); |
| 380 | +/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]); |
| 381 | +/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]); |
| 382 | +/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]); |
| 383 | +/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]); |
| 384 | +/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]); |
| 385 | +/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]); |
| 386 | +/// ``` |
| 387 | +#[macro_export] |
| 388 | +macro_rules! define_id_array { |
| 389 | + ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => { |
| 390 | + const $table_name: |
| 391 | + $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> = |
| 392 | + $crate::driver::IdArray::new( |
| 393 | + $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*)); |
| 394 | + }; |
| 395 | +} |
| 396 | + |
| 397 | +// TODO: Remove `ignore` tag from example once we go to 1.58.x. |
| 398 | +/// Defines a new constant [`IdTable`] with a concise syntax. |
| 399 | +/// |
| 400 | +/// It is meant to be used by buses and subsystems to create a similar macro with their device id |
| 401 | +/// type already specified, i.e., with fewer parameters to the end user. |
| 402 | +/// |
| 403 | +/// # Examples |
| 404 | +/// |
| 405 | +/// ```ignore |
| 406 | +/// #![feature(const_trait_impl)] |
| 407 | +/// # use kernel::{define_id_table, driver::RawDeviceId}; |
| 408 | +/// |
| 409 | +/// #[derive(Copy, Clone)] |
| 410 | +/// struct Id(u32); |
| 411 | +/// |
| 412 | +/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw |
| 413 | +/// // device id pair. |
| 414 | +/// unsafe impl const RawDeviceId for Id { |
| 415 | +/// type RawType = (u64, isize); |
| 416 | +/// const ZERO: Self::RawType = (0, 0); |
| 417 | +/// fn to_rawid(&self, offset: isize) -> Self::RawType { |
| 418 | +/// (self.0 as u64 + 1, offset) |
| 419 | +/// } |
| 420 | +/// } |
| 421 | +/// |
| 422 | +/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]); |
| 423 | +/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]); |
| 424 | +/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]); |
| 425 | +/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]); |
| 426 | +/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]); |
| 427 | +/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]); |
| 428 | +/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]); |
| 429 | +/// ``` |
| 430 | +#[macro_export] |
| 431 | +macro_rules! define_id_table { |
| 432 | + ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => { |
| 433 | + const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = { |
| 434 | + $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]); |
| 435 | + Some(ARRAY.as_table()) |
| 436 | + }; |
| 437 | + }; |
| 438 | +} |
| 439 | + |
165 | 440 | /// Custom code within device removal.
|
166 | 441 | pub trait DeviceRemoval {
|
167 | 442 | /// Cleans resources up when the device is removed.
|
|
0 commit comments