1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Advanced Configuration and Power Interface abstractions. 4 5 use crate::{bindings, device_id::RawDeviceId, prelude::*}; 6 7 /// IdTable type for ACPI drivers. 8 pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; 9 10 /// An ACPI device id. 11 #[repr(transparent)] 12 #[derive(Clone, Copy)] 13 pub struct DeviceId(bindings::acpi_device_id); 14 15 // SAFETY: 16 // * `DeviceId` is a `#[repr(transparent)` wrapper of `struct acpi_device_id` and does not add 17 // additional invariants, so it's safe to transmute to `RawType`. 18 // * `DRIVER_DATA_OFFSET` is the offset to the `data` field. 19 unsafe impl RawDeviceId for DeviceId { 20 type RawType = bindings::acpi_device_id; 21 22 const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::acpi_device_id, driver_data); 23 24 fn index(&self) -> usize { 25 self.0.driver_data 26 } 27 } 28 29 impl DeviceId { 30 const ACPI_ID_LEN: usize = 16; 31 32 /// Create a new device id from an ACPI 'id' string. 33 #[inline(always)] 34 pub const fn new(id: &'static CStr) -> Self { 35 build_assert!( 36 id.len_with_nul() <= Self::ACPI_ID_LEN, 37 "ID exceeds 16 bytes" 38 ); 39 let src = id.as_bytes_with_nul(); 40 // Replace with `bindings::acpi_device_id::default()` once stabilized for `const`. 41 // SAFETY: FFI type is valid to be zero-initialized. 42 let mut acpi: bindings::acpi_device_id = unsafe { core::mem::zeroed() }; 43 let mut i = 0; 44 while i < src.len() { 45 acpi.id[i] = src[i]; 46 i += 1; 47 } 48 49 Self(acpi) 50 } 51 } 52 53 /// Create an ACPI `IdTable` with an "alias" for modpost. 54 #[macro_export] 55 macro_rules! acpi_device_table { 56 ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { 57 const $table_name: $crate::device_id::IdArray< 58 $crate::acpi::DeviceId, 59 $id_info_type, 60 { $table_data.len() }, 61 > = $crate::device_id::IdArray::new($table_data); 62 63 $crate::module_device_table!("acpi", $module_table_name, $table_name); 64 }; 65 } 66