xref: /aosp_15_r20/external/crosvm/devices/src/ac_adapter.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
17 use crate::pci::CrosvmDeviceId;
18 use crate::BusAccessInfo;
19 use crate::BusDevice;
20 use crate::DeviceId;
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 {
new(mmio_base: u64, gpe_nr: u32) -> Self40     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.
get_init_state(&mut self)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 {
device_id(&self) -> DeviceId91     fn device_id(&self) -> DeviceId {
92         CrosvmDeviceId::AcAdapter.into()
93     }
debug_label(&self) -> String94     fn debug_label(&self) -> String {
95         "AcAdapter".to_owned()
96     }
97 
read(&mut self, info: BusAccessInfo, data: &mut [u8])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 {
to_aml_bytes(&self, bytes: &mut Vec<u8>)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