|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +//! Devicetree and Open Firmware abstractions. |
| 4 | +//! |
| 5 | +//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h) |
| 6 | +
|
| 7 | +use crate::{bindings, driver, str::BStr}; |
| 8 | + |
| 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 | +} |
| 15 | + |
| 16 | +/// Defines a const open firmware device id table that also carries per-entry data/context/info. |
| 17 | +/// |
| 18 | +/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their |
| 19 | +/// open firmware tables. |
| 20 | +/// |
| 21 | +/// # Examples |
| 22 | +/// |
| 23 | +/// ``` |
| 24 | +/// # use kernel::define_of_id_table; |
| 25 | +/// use kernel::of; |
| 26 | +/// |
| 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 | + }; |
| 37 | +} |
| 38 | + |
| 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; |
| 52 | + let mut i = 0; |
| 53 | + while i < compatible.len() { |
| 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 _; |
| 57 | + i += 1; |
| 58 | + } |
| 59 | + id.compatible[i] = b'\0' as _; |
| 60 | + id.data = offset as _; |
| 61 | + id |
| 62 | + } |
| 63 | +} |
0 commit comments