base/sys/linux/
acpi_event.rs1use std::str;
6
7use thiserror::Error;
8use zerocopy::FromBytes;
9use zerocopy::Immutable;
10use zerocopy::KnownLayout;
11
12use super::netlink::*;
13
14const ACPI_EVENT_SIZE: usize = std::mem::size_of::<AcpiGenlEvent>();
15const GENL_HDRLEN: usize = std::mem::size_of::<GenlMsgHdr>();
16const NLA_HDRLEN: usize = std::mem::size_of::<NlAttr>();
17
18#[derive(Error, Debug)]
19pub enum AcpiEventError {
20 #[error("GenmsghdrCmd or NlAttrType inappropriate for acpi event")]
21 TypeAttrMissmatch,
22 #[error("Something goes wrong: msg_len {0} is not correct")]
23 InvalidMsgLen(usize),
24}
25type Result<T> = std::result::Result<T, AcpiEventError>;
26
27#[allow(dead_code)]
29enum NlAttrType {
30 AcpiGenlAttrUnspec,
31 AcpiGenlAttrEvent, AcpiGenlAttrMax,
33}
34
35#[allow(dead_code)]
37enum GenmsghdrCmd {
38 AcpiGenlCmdUnspec,
39 AcpiGenlCmdEvent, AcpiGenlCmdMax,
41}
42
43#[repr(C)]
44#[derive(Copy, Clone, FromBytes, Immutable, KnownLayout)]
45struct AcpiGenlEvent {
46 device_class: [u8; 20],
47 bus_id: [u8; 15],
48 _type: u32,
49 data: u32,
50}
51
52pub struct AcpiNotifyEvent {
53 pub device_class: String,
54 pub bus_id: String,
55 pub _type: u32,
56 pub data: u32,
57}
58
59impl AcpiNotifyEvent {
60 pub fn new(netlink_message: NetlinkMessage) -> Result<Self> {
62 let msg_len = netlink_message.data.len();
63 if msg_len != GENL_HDRLEN + NLA_HDRLEN + ACPI_EVENT_SIZE {
64 return Err(AcpiEventError::InvalidMsgLen(msg_len));
65 }
66
67 let (genl_hdr, nl_attr) = GenlMsgHdr::read_from_prefix(netlink_message.data)
68 .expect("unable to get GenlMsgHdr from slice");
69
70 let (nl_attr, body) =
71 NlAttr::read_from_prefix(nl_attr).expect("unable to get NlAttr from slice");
72
73 if genl_hdr.cmd != GenmsghdrCmd::AcpiGenlCmdEvent as u8
75 || nl_attr._type != NlAttrType::AcpiGenlAttrEvent as u16
76 {
77 return Err(AcpiEventError::TypeAttrMissmatch);
78 }
79
80 let acpi_event =
81 AcpiGenlEvent::read_from_bytes(body).expect("unable to get AcpiGenlEvent from slice");
82
83 Ok(AcpiNotifyEvent {
84 device_class: strip_padding(&acpi_event.device_class).to_owned(),
85 bus_id: strip_padding(&acpi_event.bus_id).to_owned(),
86 _type: acpi_event._type,
87 data: acpi_event.data,
88 })
89 }
90}
91
92fn strip_padding(b: &[u8]) -> &str {
95 let pos = b
97 .iter()
98 .position(|&c| c == 0)
99 .expect("`b` doesn't contain any nul bytes");
100
101 str::from_utf8(&b[..pos]).unwrap()
102}