Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/ac_adapter.rs
5392 views
1
// Copyright 2023 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
// The ACPI AC adapter device (ACPI0003) description can be found in ACPI specification,
6
// section: 10.3. The AC adapter status change is signalized by generating associated GPE, which
7
// Notify()'s AC adapter device in the ACPI name space.
8
9
use std::fs::read_to_string;
10
use std::path::PathBuf;
11
12
use acpi_tables::aml;
13
use acpi_tables::aml::Aml;
14
use anyhow::Context;
15
use base::warn;
16
use vm_control::DeviceId;
17
use vm_control::PlatformDeviceId;
18
19
use crate::BusAccessInfo;
20
use crate::BusDevice;
21
use crate::Suspendable;
22
23
pub const ACDC_VIRT_MMIO_SIZE: u64 = 0x10;
24
25
/// ACDC Virt MMIO offset
26
const ACDC_ACEX: u32 = 0;
27
const _ACDC_RESERVED2: u32 = 0x4;
28
const _ACDC_RESERVED3: u32 = 0x8;
29
const _ACDC_RESERVED4: u32 = 0xc;
30
31
const ACDC_ACEX_UNINIT: u32 = 0xff;
32
33
pub struct AcAdapter {
34
pub acex: u32,
35
mmio_base: u64,
36
pub gpe_nr: u32,
37
}
38
39
impl AcAdapter {
40
pub fn new(mmio_base: u64, gpe_nr: u32) -> Self {
41
AcAdapter {
42
acex: ACDC_ACEX_UNINIT,
43
mmio_base,
44
gpe_nr,
45
}
46
}
47
48
// The AC adapter state update is triggered upon handling "ac_adapter" acpi event, nevertheless
49
// the init value is retrieved from host's sysfs. Determining it from AcAdapter::new would be
50
// racy since after AcAdapter creation but before acpi listener is activated any status change
51
// will be lost. Determining init state in such way will be triggered only once during guest
52
// driver probe.
53
fn get_init_state(&mut self) {
54
// Find host AC adapter (ACPI0003 HID) and read its state.
55
// e.g. hid /sys/class/power_supply/ADP1/device/hid
56
// state /sys/class/power_supply/ADP1/online
57
let mut ac_status = None;
58
let mut host_sysfs = PathBuf::new();
59
host_sysfs.push("/sys/class/power_supply/");
60
for entry in host_sysfs
61
.read_dir()
62
.expect("read_dir call failed")
63
.flatten()
64
{
65
let hid_path = entry.path().join("device/hid");
66
if hid_path.exists() {
67
if read_to_string(hid_path.as_path())
68
.with_context(|| format!("failed to read {}", hid_path.display()))
69
.unwrap()
70
.contains("ACPI0003")
71
{
72
ac_status = Some(
73
read_to_string(entry.path().join("online"))
74
.unwrap()
75
.trim()
76
.parse::<u32>()
77
.unwrap(),
78
);
79
}
80
}
81
}
82
83
if ac_status.is_none() {
84
warn!("Couldn't get ACPI0003 AC adapter state");
85
}
86
self.acex = ac_status.unwrap_or(0);
87
}
88
}
89
90
impl BusDevice for AcAdapter {
91
fn device_id(&self) -> DeviceId {
92
PlatformDeviceId::AcAdapter.into()
93
}
94
fn debug_label(&self) -> String {
95
"AcAdapter".to_owned()
96
}
97
98
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
99
if data.len() != std::mem::size_of::<u32>() {
100
warn!(
101
"{}: unsupported read length {}, only support 4bytes read",
102
self.debug_label(),
103
data.len()
104
);
105
return;
106
}
107
108
let val = match info.offset as u32 {
109
ACDC_ACEX => {
110
if self.acex == ACDC_ACEX_UNINIT {
111
self.get_init_state();
112
}
113
self.acex
114
}
115
_ => {
116
warn!("{}: unsupported read address {}", self.debug_label(), info);
117
return;
118
}
119
};
120
121
let val_arr = val.to_le_bytes();
122
data.copy_from_slice(&val_arr);
123
}
124
}
125
126
impl Aml for AcAdapter {
127
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
128
aml::Device::new(
129
"ACDC".into(),
130
vec![
131
&aml::Name::new("_HID".into(), &"ACPI0003"),
132
&aml::OpRegion::new(
133
"VREG".into(),
134
aml::OpRegionSpace::SystemMemory,
135
&self.mmio_base,
136
&(16_u32),
137
),
138
&aml::Field::new(
139
"VREG".into(),
140
aml::FieldAccessType::DWord,
141
aml::FieldLockRule::Lock,
142
aml::FieldUpdateRule::Preserve,
143
vec![aml::FieldEntry::Named(*b"ACEX", 32)],
144
),
145
&aml::Method::new(
146
"_PSR".into(),
147
0,
148
false,
149
vec![&aml::Return::new(&aml::Name::new_field_name("ACEX"))],
150
),
151
&aml::Method::new("_STA".into(), 0, false, vec![&aml::Return::new(&0xfu8)]),
152
],
153
)
154
.to_aml_bytes(bytes);
155
aml::Scope::new(
156
"_GPE".into(),
157
vec![&aml::Method::new(
158
format!("_E{:02X}", self.gpe_nr).as_str().into(),
159
0,
160
false,
161
vec![&aml::Notify::new(&aml::Path::new("ACDC"), &0x80u8)],
162
)],
163
)
164
.to_aml_bytes(bytes);
165
}
166
}
167
168
impl Suspendable for AcAdapter {}
169
170