Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/acpi_event.rs
5394 views
1
// Copyright 2022 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::str;
6
7
use thiserror::Error;
8
use zerocopy::FromBytes;
9
use zerocopy::Immutable;
10
use zerocopy::KnownLayout;
11
12
use super::netlink::*;
13
14
const ACPI_EVENT_SIZE: usize = std::mem::size_of::<AcpiGenlEvent>();
15
const GENL_HDRLEN: usize = std::mem::size_of::<GenlMsgHdr>();
16
const NLA_HDRLEN: usize = std::mem::size_of::<NlAttr>();
17
18
#[derive(Error, Debug)]
19
pub 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
}
25
type Result<T> = std::result::Result<T, AcpiEventError>;
26
27
/// attributes of AcpiGenlFamily
28
#[allow(dead_code)]
29
enum NlAttrType {
30
AcpiGenlAttrUnspec,
31
AcpiGenlAttrEvent, // acpi_event (needed by user space)
32
AcpiGenlAttrMax,
33
}
34
35
/// commands supported by the AcpiGenlFamily
36
#[allow(dead_code)]
37
enum GenmsghdrCmd {
38
AcpiGenlCmdUnspec,
39
AcpiGenlCmdEvent, // kernel->user notifications for acpi_events
40
AcpiGenlCmdMax,
41
}
42
43
#[repr(C)]
44
#[derive(Copy, Clone, FromBytes, Immutable, KnownLayout)]
45
struct AcpiGenlEvent {
46
device_class: [u8; 20],
47
bus_id: [u8; 15],
48
_type: u32,
49
data: u32,
50
}
51
52
pub struct AcpiNotifyEvent {
53
pub device_class: String,
54
pub bus_id: String,
55
pub _type: u32,
56
pub data: u32,
57
}
58
59
impl AcpiNotifyEvent {
60
/// Create acpi event by decapsulating it from NetlinkMessage.
61
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
// Sanity check that the headers have correct for acpi event `cmd` and `_type`
74
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
92
// Like `CStr::from_bytes_with_nul` but strips any bytes starting from first '\0'-byte and
93
// returns &str. Panics if `b` doesn't contain any '\0' bytes.
94
fn strip_padding(b: &[u8]) -> &str {
95
// It would be nice if we could use memchr here but that's locked behind an unstable gate.
96
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
}
103
104