|
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