|
4 | 4 | //! |
5 | 5 | //! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h) |
6 | 6 |
|
7 | | -use crate::{bindings, c_types, str::CStr}; |
| 7 | +use crate::{bindings, driver, str::BStr}; |
8 | 8 |
|
9 | | -use core::ops::Deref; |
10 | | -use core::ptr; |
| 9 | +/// An open firmware device id. |
| 10 | +#[derive(Clone, Copy)] |
| 11 | +pub enum DeviceId { |
| 12 | + /// An open firmware device id where only a compatible string is specified. |
| 13 | + Compatible(&'static BStr), |
| 14 | +} |
11 | 15 |
|
12 | | -/// A kernel Open Firmware / devicetree match table. |
13 | | -/// |
14 | | -/// Can only exist as an `&OfMatchTable` reference (akin to `&str` or |
15 | | -/// `&Path` in Rust std). |
| 16 | +/// Defines a const open firmware device id table that also carries per-entry data/context/info. |
16 | 17 | /// |
17 | | -/// # Invariants |
| 18 | +/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their |
| 19 | +/// open firmware tables. |
18 | 20 | /// |
19 | | -/// The inner reference points to a sentinel-terminated C array. |
20 | | -#[repr(transparent)] |
21 | | -pub struct OfMatchTable(bindings::of_device_id); |
22 | | - |
23 | | -impl OfMatchTable { |
24 | | - /// Returns the table as a reference to a static lifetime, sentinel-terminated C array. |
25 | | - /// |
26 | | - /// This is suitable to be coerced into the kernel's `of_match_table` field. |
27 | | - pub fn as_ptr(&'static self) -> &'static bindings::of_device_id { |
28 | | - // The inner reference points to a sentinel-terminated C array, as per |
29 | | - // the type invariant. |
30 | | - &self.0 |
31 | | - } |
32 | | -} |
33 | | - |
34 | | -/// An Open Firmware Match Table that can be constructed at build time. |
| 21 | +/// # Examples |
35 | 22 | /// |
36 | | -/// # Invariants |
| 23 | +/// ``` |
| 24 | +/// # use kernel::define_of_id_table; |
| 25 | +/// use kernel::of; |
37 | 26 | /// |
38 | | -/// `sentinel` always contains zeroes. |
39 | | -#[repr(C)] |
40 | | -pub struct ConstOfMatchTable<const N: usize> { |
41 | | - table: [bindings::of_device_id; N], |
42 | | - sentinel: bindings::of_device_id, |
| 27 | +/// define_of_id_table! {u32, [ |
| 28 | +/// (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)), |
| 29 | +/// (of::DeviceId::Compatible(b"test-device3"), None), |
| 30 | +/// ]}; |
| 31 | +/// ``` |
| 32 | +#[macro_export] |
| 33 | +macro_rules! define_of_id_table { |
| 34 | + ($data_type:ty, $($t:tt)*) => { |
| 35 | + $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*); |
| 36 | + }; |
43 | 37 | } |
44 | 38 |
|
45 | | -impl<const N: usize> ConstOfMatchTable<N> { |
46 | | - /// Creates a new Open Firmware Match Table from a list of compatible strings. |
47 | | - pub const fn new_const(compatibles: [&'static CStr; N]) -> Self { |
48 | | - let mut table = [Self::zeroed_of_device_id(); N]; |
49 | | - let mut i = 0; |
50 | | - while i < N { |
51 | | - table[i] = Self::new_of_device_id(compatibles[i]); |
52 | | - i += 1; |
53 | | - } |
54 | | - Self { |
55 | | - table, |
56 | | - // INVARIANTS: we zero the sentinel here, and never change it |
57 | | - // anywhere. Therefore it always contains zeroes. |
58 | | - sentinel: Self::zeroed_of_device_id(), |
59 | | - } |
60 | | - } |
61 | | - |
62 | | - const fn zeroed_of_device_id() -> bindings::of_device_id { |
63 | | - bindings::of_device_id { |
64 | | - name: [0; 32], |
65 | | - type_: [0; 32], |
66 | | - compatible: [0; 128], |
67 | | - data: ptr::null(), |
68 | | - } |
69 | | - } |
70 | | - |
71 | | - const fn new_of_device_id(compatible: &'static CStr) -> bindings::of_device_id { |
72 | | - let mut id = Self::zeroed_of_device_id(); |
73 | | - let compatible = compatible.as_bytes_with_nul(); |
| 39 | +// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`. |
| 40 | +unsafe impl const driver::RawDeviceId for DeviceId { |
| 41 | + type RawType = bindings::of_device_id; |
| 42 | + const ZERO: Self::RawType = bindings::of_device_id { |
| 43 | + name: [0; 32], |
| 44 | + type_: [0; 32], |
| 45 | + compatible: [0; 128], |
| 46 | + data: core::ptr::null(), |
| 47 | + }; |
| 48 | + |
| 49 | + fn to_rawid(&self, offset: isize) -> Self::RawType { |
| 50 | + let DeviceId::Compatible(compatible) = self; |
| 51 | + let mut id = Self::ZERO; |
74 | 52 | let mut i = 0; |
75 | 53 | while i < compatible.len() { |
76 | | - // If `compatible` does not fit in `id.compatible`, an |
77 | | - // "index out of bounds" build time error will be triggered. |
78 | | - id.compatible[i] = compatible[i] as c_types::c_char; |
| 54 | + // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time |
| 55 | + // error will be triggered. |
| 56 | + id.compatible[i] = compatible[i] as _; |
79 | 57 | i += 1; |
80 | 58 | } |
| 59 | + id.compatible[i] = b'\0' as _; |
| 60 | + id.data = offset as _; |
81 | 61 | id |
82 | 62 | } |
83 | 63 | } |
84 | | - |
85 | | -impl<const N: usize> Deref for ConstOfMatchTable<N> { |
86 | | - type Target = OfMatchTable; |
87 | | - |
88 | | - fn deref(&self) -> &OfMatchTable { |
89 | | - // INVARIANTS: `head` points to a sentinel-terminated C array, |
90 | | - // as per the `ConstOfMatchTable` type invariant, therefore |
91 | | - // `&OfMatchTable`'s inner reference will point to a sentinel-terminated C array. |
92 | | - let head = &self.table[0] as *const bindings::of_device_id as *const OfMatchTable; |
93 | | - |
94 | | - // SAFETY: The returned reference must remain valid for the lifetime of `self`. |
95 | | - // The raw pointer `head` points to memory inside `self`. So the reference created |
96 | | - // from this raw pointer has the same lifetime as `self`. |
97 | | - // Therefore this reference remains valid for the lifetime of `self`, and |
98 | | - // is safe to return. |
99 | | - unsafe { &*head } |
100 | | - } |
101 | | -} |
0 commit comments