xref: /aosp_15_r20/external/crosvm/devices/src/bat.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use acpi_tables::aml;
8*bb4ee6a4SAndroid Build Coastguard Worker use acpi_tables::aml::Aml;
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail;
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
11*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
20*bb4ee6a4SAndroid Build Coastguard Worker use power_monitor::BatteryStatus;
21*bb4ee6a4SAndroid Build Coastguard Worker use power_monitor::CreatePowerClientFn;
22*bb4ee6a4SAndroid Build Coastguard Worker use power_monitor::CreatePowerMonitorFn;
23*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
24*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
25*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
26*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
27*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
28*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BatConfig;
29*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BatControlCommand;
30*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BatControlResult;
31*bb4ee6a4SAndroid Build Coastguard Worker 
32*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::CrosvmDeviceId;
33*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusAccessInfo;
34*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusDevice;
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceId;
36*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqLevelEvent;
37*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
38*bb4ee6a4SAndroid Build Coastguard Worker 
39*bb4ee6a4SAndroid Build Coastguard Worker /// Errors for battery devices.
40*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
41*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
42*bb4ee6a4SAndroid Build Coastguard Worker pub enum BatteryError {
43*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Non 32-bit mmio address space")]
44*bb4ee6a4SAndroid Build Coastguard Worker     Non32BitMmioAddress,
45*bb4ee6a4SAndroid Build Coastguard Worker }
46*bb4ee6a4SAndroid Build Coastguard Worker 
47*bb4ee6a4SAndroid Build Coastguard Worker type Result<T> = std::result::Result<T, BatteryError>;
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker /// the GoldFish Battery MMIO length.
50*bb4ee6a4SAndroid Build Coastguard Worker pub const GOLDFISHBAT_MMIO_LEN: u64 = 0x1000;
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Serialize, Deserialize)]
53*bb4ee6a4SAndroid Build Coastguard Worker struct GoldfishBatteryState {
54*bb4ee6a4SAndroid Build Coastguard Worker     // interrupt state
55*bb4ee6a4SAndroid Build Coastguard Worker     int_status: u32,
56*bb4ee6a4SAndroid Build Coastguard Worker     int_enable: u32,
57*bb4ee6a4SAndroid Build Coastguard Worker     // AC state
58*bb4ee6a4SAndroid Build Coastguard Worker     ac_online: u32,
59*bb4ee6a4SAndroid Build Coastguard Worker     // Battery state
60*bb4ee6a4SAndroid Build Coastguard Worker     status: u32,
61*bb4ee6a4SAndroid Build Coastguard Worker     health: u32,
62*bb4ee6a4SAndroid Build Coastguard Worker     present: u32,
63*bb4ee6a4SAndroid Build Coastguard Worker     capacity: u32,
64*bb4ee6a4SAndroid Build Coastguard Worker     voltage: u32,
65*bb4ee6a4SAndroid Build Coastguard Worker     current: u32,
66*bb4ee6a4SAndroid Build Coastguard Worker     charge_counter: u32,
67*bb4ee6a4SAndroid Build Coastguard Worker     charge_full: u32,
68*bb4ee6a4SAndroid Build Coastguard Worker     initialized: bool,
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! create_battery_func {
72*bb4ee6a4SAndroid Build Coastguard Worker     // $property: the battery property which is going to be modified.
73*bb4ee6a4SAndroid Build Coastguard Worker     // $int: the interrupt status which is going to be set to notify the guest.
74*bb4ee6a4SAndroid Build Coastguard Worker     ($fn:ident, $property:ident, $int:ident) => {
75*bb4ee6a4SAndroid Build Coastguard Worker         pub(crate) fn $fn(&mut self, value: u32) -> bool {
76*bb4ee6a4SAndroid Build Coastguard Worker             let old = std::mem::replace(&mut self.$property, value);
77*bb4ee6a4SAndroid Build Coastguard Worker             old != self.$property && self.set_int_status($int)
78*bb4ee6a4SAndroid Build Coastguard Worker         }
79*bb4ee6a4SAndroid Build Coastguard Worker     };
80*bb4ee6a4SAndroid Build Coastguard Worker }
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker impl GoldfishBatteryState {
set_int_status(&mut self, mask: u32) -> bool83*bb4ee6a4SAndroid Build Coastguard Worker     fn set_int_status(&mut self, mask: u32) -> bool {
84*bb4ee6a4SAndroid Build Coastguard Worker         if ((self.int_enable & mask) != 0) && ((self.int_status & mask) == 0) {
85*bb4ee6a4SAndroid Build Coastguard Worker             self.int_status |= mask;
86*bb4ee6a4SAndroid Build Coastguard Worker             return true;
87*bb4ee6a4SAndroid Build Coastguard Worker         }
88*bb4ee6a4SAndroid Build Coastguard Worker         false
89*bb4ee6a4SAndroid Build Coastguard Worker     }
90*bb4ee6a4SAndroid Build Coastguard Worker 
int_status(&self) -> u3291*bb4ee6a4SAndroid Build Coastguard Worker     fn int_status(&self) -> u32 {
92*bb4ee6a4SAndroid Build Coastguard Worker         self.int_status
93*bb4ee6a4SAndroid Build Coastguard Worker     }
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_ac_online, ac_online, AC_STATUS_CHANGED);
96*bb4ee6a4SAndroid Build Coastguard Worker 
97*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_status, status, BATTERY_STATUS_CHANGED);
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_health, health, BATTERY_STATUS_CHANGED);
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_present, present, BATTERY_STATUS_CHANGED);
102*bb4ee6a4SAndroid Build Coastguard Worker 
103*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_capacity, capacity, BATTERY_STATUS_CHANGED);
104*bb4ee6a4SAndroid Build Coastguard Worker 
105*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_voltage, voltage, BATTERY_STATUS_CHANGED);
106*bb4ee6a4SAndroid Build Coastguard Worker 
107*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_current, current, BATTERY_STATUS_CHANGED);
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_charge_counter, charge_counter, BATTERY_STATUS_CHANGED);
110*bb4ee6a4SAndroid Build Coastguard Worker 
111*bb4ee6a4SAndroid Build Coastguard Worker     create_battery_func!(set_charge_full, charge_full, BATTERY_STATUS_CHANGED);
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker /// GoldFish Battery state
115*bb4ee6a4SAndroid Build Coastguard Worker pub struct GoldfishBattery {
116*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<Mutex<GoldfishBatteryState>>,
117*bb4ee6a4SAndroid Build Coastguard Worker     mmio_base: u32,
118*bb4ee6a4SAndroid Build Coastguard Worker     irq_num: u32,
119*bb4ee6a4SAndroid Build Coastguard Worker     irq_evt: IrqLevelEvent,
120*bb4ee6a4SAndroid Build Coastguard Worker     activated: bool,
121*bb4ee6a4SAndroid Build Coastguard Worker     monitor_thread: Option<WorkerThread<()>>,
122*bb4ee6a4SAndroid Build Coastguard Worker     tube: Option<Tube>,
123*bb4ee6a4SAndroid Build Coastguard Worker     create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
124*bb4ee6a4SAndroid Build Coastguard Worker     create_powerd_client: Option<Box<dyn CreatePowerClientFn>>,
125*bb4ee6a4SAndroid Build Coastguard Worker     // battery_config is used for goldfish battery to report fake battery to the guest.
126*bb4ee6a4SAndroid Build Coastguard Worker     battery_config: Arc<Mutex<BatConfig>>,
127*bb4ee6a4SAndroid Build Coastguard Worker }
128*bb4ee6a4SAndroid Build Coastguard Worker 
129*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)]
130*bb4ee6a4SAndroid Build Coastguard Worker struct GoldfishBatterySnapshot {
131*bb4ee6a4SAndroid Build Coastguard Worker     state: GoldfishBatteryState,
132*bb4ee6a4SAndroid Build Coastguard Worker     mmio_base: u32,
133*bb4ee6a4SAndroid Build Coastguard Worker     irq_num: u32,
134*bb4ee6a4SAndroid Build Coastguard Worker     activated: bool,
135*bb4ee6a4SAndroid Build Coastguard Worker }
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker /// Goldfish Battery MMIO offset
138*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_INT_STATUS: u32 = 0;
139*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_INT_ENABLE: u32 = 0x4;
140*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_AC_ONLINE: u32 = 0x8;
141*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_STATUS: u32 = 0xC;
142*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_HEALTH: u32 = 0x10;
143*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_PRESENT: u32 = 0x14;
144*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CAPACITY: u32 = 0x18;
145*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_VOLTAGE: u32 = 0x1C;
146*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_TEMP: u32 = 0x20;
147*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CHARGE_COUNTER: u32 = 0x24;
148*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_VOLTAGE_MAX: u32 = 0x28;
149*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CURRENT_MAX: u32 = 0x2C;
150*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CURRENT_NOW: u32 = 0x30;
151*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CURRENT_AVG: u32 = 0x34;
152*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CHARGE_FULL_UAH: u32 = 0x38;
153*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_CYCLE_COUNT: u32 = 0x40;
154*bb4ee6a4SAndroid Build Coastguard Worker 
155*bb4ee6a4SAndroid Build Coastguard Worker /// Goldfish Battery interrupt bits
156*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_STATUS_CHANGED: u32 = 1 << 0;
157*bb4ee6a4SAndroid Build Coastguard Worker const AC_STATUS_CHANGED: u32 = 1 << 1;
158*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_INT_MASK: u32 = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED;
159*bb4ee6a4SAndroid Build Coastguard Worker 
160*bb4ee6a4SAndroid Build Coastguard Worker /// Goldfish Battery status
161*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_STATUS_VAL_UNKNOWN: u32 = 0;
162*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_STATUS_VAL_CHARGING: u32 = 1;
163*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_STATUS_VAL_DISCHARGING: u32 = 2;
164*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_STATUS_VAL_NOT_CHARGING: u32 = 3;
165*bb4ee6a4SAndroid Build Coastguard Worker 
166*bb4ee6a4SAndroid Build Coastguard Worker /// Goldfish Battery health
167*bb4ee6a4SAndroid Build Coastguard Worker const BATTERY_HEALTH_VAL_UNKNOWN: u32 = 0;
168*bb4ee6a4SAndroid Build Coastguard Worker 
169*bb4ee6a4SAndroid Build Coastguard Worker // Goldfish ac online status
170*bb4ee6a4SAndroid Build Coastguard Worker const AC_ONLINE_VAL_OFFLINE: u32 = 0;
171*bb4ee6a4SAndroid Build Coastguard Worker 
172*bb4ee6a4SAndroid Build Coastguard Worker #[derive(EventToken)]
173*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) enum Token {
174*bb4ee6a4SAndroid Build Coastguard Worker     Commands,
175*bb4ee6a4SAndroid Build Coastguard Worker     Resample,
176*bb4ee6a4SAndroid Build Coastguard Worker     Kill,
177*bb4ee6a4SAndroid Build Coastguard Worker     Monitor,
178*bb4ee6a4SAndroid Build Coastguard Worker }
179*bb4ee6a4SAndroid Build Coastguard Worker 
command_monitor( tube: Tube, irq_evt: IrqLevelEvent, kill_evt: Event, state: Arc<Mutex<GoldfishBatteryState>>, create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>, battery_config: Arc<Mutex<BatConfig>>, )180*bb4ee6a4SAndroid Build Coastguard Worker fn command_monitor(
181*bb4ee6a4SAndroid Build Coastguard Worker     tube: Tube,
182*bb4ee6a4SAndroid Build Coastguard Worker     irq_evt: IrqLevelEvent,
183*bb4ee6a4SAndroid Build Coastguard Worker     kill_evt: Event,
184*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<Mutex<GoldfishBatteryState>>,
185*bb4ee6a4SAndroid Build Coastguard Worker     create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
186*bb4ee6a4SAndroid Build Coastguard Worker     battery_config: Arc<Mutex<BatConfig>>,
187*bb4ee6a4SAndroid Build Coastguard Worker ) {
188*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
189*bb4ee6a4SAndroid Build Coastguard Worker         (&tube, Token::Commands),
190*bb4ee6a4SAndroid Build Coastguard Worker         (irq_evt.get_resample(), Token::Resample),
191*bb4ee6a4SAndroid Build Coastguard Worker         (&kill_evt, Token::Kill),
192*bb4ee6a4SAndroid Build Coastguard Worker     ]) {
193*bb4ee6a4SAndroid Build Coastguard Worker         Ok(pc) => pc,
194*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
195*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed to build WaitContext: {}", e);
196*bb4ee6a4SAndroid Build Coastguard Worker             return;
197*bb4ee6a4SAndroid Build Coastguard Worker         }
198*bb4ee6a4SAndroid Build Coastguard Worker     };
199*bb4ee6a4SAndroid Build Coastguard Worker 
200*bb4ee6a4SAndroid Build Coastguard Worker     let mut power_monitor = match create_power_monitor {
201*bb4ee6a4SAndroid Build Coastguard Worker         Some(f) => match f() {
202*bb4ee6a4SAndroid Build Coastguard Worker             Ok(p) => match wait_ctx.add(p.get_read_notifier(), Token::Monitor) {
203*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(()) => Some(p),
204*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
205*bb4ee6a4SAndroid Build Coastguard Worker                     error!("failed to add power monitor to poll context: {}", e);
206*bb4ee6a4SAndroid Build Coastguard Worker                     None
207*bb4ee6a4SAndroid Build Coastguard Worker                 }
208*bb4ee6a4SAndroid Build Coastguard Worker             },
209*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
210*bb4ee6a4SAndroid Build Coastguard Worker                 error!("failed to create power monitor: {}", e);
211*bb4ee6a4SAndroid Build Coastguard Worker                 None
212*bb4ee6a4SAndroid Build Coastguard Worker             }
213*bb4ee6a4SAndroid Build Coastguard Worker         },
214*bb4ee6a4SAndroid Build Coastguard Worker         None => None,
215*bb4ee6a4SAndroid Build Coastguard Worker     };
216*bb4ee6a4SAndroid Build Coastguard Worker 
217*bb4ee6a4SAndroid Build Coastguard Worker     'poll: loop {
218*bb4ee6a4SAndroid Build Coastguard Worker         let events = match wait_ctx.wait() {
219*bb4ee6a4SAndroid Build Coastguard Worker             Ok(v) => v,
220*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
221*bb4ee6a4SAndroid Build Coastguard Worker                 error!("error while polling for events: {}", e);
222*bb4ee6a4SAndroid Build Coastguard Worker                 break;
223*bb4ee6a4SAndroid Build Coastguard Worker             }
224*bb4ee6a4SAndroid Build Coastguard Worker         };
225*bb4ee6a4SAndroid Build Coastguard Worker 
226*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
227*bb4ee6a4SAndroid Build Coastguard Worker             match event.token {
228*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Commands => {
229*bb4ee6a4SAndroid Build Coastguard Worker                     let req = match tube.recv() {
230*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(req) => req,
231*bb4ee6a4SAndroid Build Coastguard Worker                         Err(e) => {
232*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to receive request: {}", e);
233*bb4ee6a4SAndroid Build Coastguard Worker                             continue;
234*bb4ee6a4SAndroid Build Coastguard Worker                         }
235*bb4ee6a4SAndroid Build Coastguard Worker                     };
236*bb4ee6a4SAndroid Build Coastguard Worker 
237*bb4ee6a4SAndroid Build Coastguard Worker                     let mut bat_config = battery_config.lock();
238*bb4ee6a4SAndroid Build Coastguard Worker                     let mut bat_state = state.lock();
239*bb4ee6a4SAndroid Build Coastguard Worker                     let inject_irq = match req {
240*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::SetStatus(status) => bat_state.set_status(status.into()),
241*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::SetHealth(health) => bat_state.set_health(health.into()),
242*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::SetPresent(present) => {
243*bb4ee6a4SAndroid Build Coastguard Worker                             let v = present != 0;
244*bb4ee6a4SAndroid Build Coastguard Worker                             bat_state.set_present(v.into())
245*bb4ee6a4SAndroid Build Coastguard Worker                         }
246*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::SetCapacity(capacity) => {
247*bb4ee6a4SAndroid Build Coastguard Worker                             let v = std::cmp::min(capacity, 100);
248*bb4ee6a4SAndroid Build Coastguard Worker                             bat_state.set_capacity(v)
249*bb4ee6a4SAndroid Build Coastguard Worker                         }
250*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::SetACOnline(ac_online) => {
251*bb4ee6a4SAndroid Build Coastguard Worker                             let v = ac_online != 0;
252*bb4ee6a4SAndroid Build Coastguard Worker                             bat_state.set_ac_online(v.into())
253*bb4ee6a4SAndroid Build Coastguard Worker                         }
254*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::SetFakeBatConfig(max_capacity) => {
255*bb4ee6a4SAndroid Build Coastguard Worker                             let max_capacity = std::cmp::min(max_capacity, 100);
256*bb4ee6a4SAndroid Build Coastguard Worker                             *bat_config = BatConfig::Fake { max_capacity };
257*bb4ee6a4SAndroid Build Coastguard Worker                             true
258*bb4ee6a4SAndroid Build Coastguard Worker                         }
259*bb4ee6a4SAndroid Build Coastguard Worker                         BatControlCommand::CancelFakeConfig => {
260*bb4ee6a4SAndroid Build Coastguard Worker                             *bat_config = BatConfig::Real;
261*bb4ee6a4SAndroid Build Coastguard Worker                             true
262*bb4ee6a4SAndroid Build Coastguard Worker                         }
263*bb4ee6a4SAndroid Build Coastguard Worker                     };
264*bb4ee6a4SAndroid Build Coastguard Worker 
265*bb4ee6a4SAndroid Build Coastguard Worker                     if inject_irq {
266*bb4ee6a4SAndroid Build Coastguard Worker                         let _ = irq_evt.trigger();
267*bb4ee6a4SAndroid Build Coastguard Worker                     }
268*bb4ee6a4SAndroid Build Coastguard Worker 
269*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = tube.send(&BatControlResult::Ok) {
270*bb4ee6a4SAndroid Build Coastguard Worker                         error!("failed to send response: {}", e);
271*bb4ee6a4SAndroid Build Coastguard Worker                     }
272*bb4ee6a4SAndroid Build Coastguard Worker                 }
273*bb4ee6a4SAndroid Build Coastguard Worker 
274*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Monitor => {
275*bb4ee6a4SAndroid Build Coastguard Worker                     // Safe because power_monitor must be populated if Token::Monitor is triggered.
276*bb4ee6a4SAndroid Build Coastguard Worker                     let power_monitor = power_monitor.as_mut().unwrap();
277*bb4ee6a4SAndroid Build Coastguard Worker 
278*bb4ee6a4SAndroid Build Coastguard Worker                     let data = match power_monitor.read_message() {
279*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(Some(d)) => d,
280*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(None) => continue,
281*bb4ee6a4SAndroid Build Coastguard Worker                         Err(e) => {
282*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to read new power data: {}", e);
283*bb4ee6a4SAndroid Build Coastguard Worker                             continue;
284*bb4ee6a4SAndroid Build Coastguard Worker                         }
285*bb4ee6a4SAndroid Build Coastguard Worker                     };
286*bb4ee6a4SAndroid Build Coastguard Worker 
287*bb4ee6a4SAndroid Build Coastguard Worker                     let mut bat_state = state.lock();
288*bb4ee6a4SAndroid Build Coastguard Worker 
289*bb4ee6a4SAndroid Build Coastguard Worker                     // Each set_* function called below returns true when interrupt bits
290*bb4ee6a4SAndroid Build Coastguard Worker                     // (*_STATUS_CHANGED) changed. If `inject_irq` is true after we attempt to
291*bb4ee6a4SAndroid Build Coastguard Worker                     // update each field, inject an interrupt.
292*bb4ee6a4SAndroid Build Coastguard Worker                     let mut inject_irq = bat_state.set_ac_online(data.ac_online.into());
293*bb4ee6a4SAndroid Build Coastguard Worker 
294*bb4ee6a4SAndroid Build Coastguard Worker                     match data.battery {
295*bb4ee6a4SAndroid Build Coastguard Worker                         Some(battery_data) => {
296*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_capacity(battery_data.percent);
297*bb4ee6a4SAndroid Build Coastguard Worker                             let battery_status = match battery_data.status {
298*bb4ee6a4SAndroid Build Coastguard Worker                                 BatteryStatus::Unknown => BATTERY_STATUS_VAL_UNKNOWN,
299*bb4ee6a4SAndroid Build Coastguard Worker                                 BatteryStatus::Charging => BATTERY_STATUS_VAL_CHARGING,
300*bb4ee6a4SAndroid Build Coastguard Worker                                 BatteryStatus::Discharging => BATTERY_STATUS_VAL_DISCHARGING,
301*bb4ee6a4SAndroid Build Coastguard Worker                                 BatteryStatus::NotCharging => BATTERY_STATUS_VAL_NOT_CHARGING,
302*bb4ee6a4SAndroid Build Coastguard Worker                             };
303*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_status(battery_status);
304*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_voltage(battery_data.voltage);
305*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_current(battery_data.current);
306*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_charge_counter(battery_data.charge_counter);
307*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_charge_full(battery_data.charge_full);
308*bb4ee6a4SAndroid Build Coastguard Worker                         }
309*bb4ee6a4SAndroid Build Coastguard Worker                         None => {
310*bb4ee6a4SAndroid Build Coastguard Worker                             inject_irq |= bat_state.set_present(0);
311*bb4ee6a4SAndroid Build Coastguard Worker                         }
312*bb4ee6a4SAndroid Build Coastguard Worker                     }
313*bb4ee6a4SAndroid Build Coastguard Worker 
314*bb4ee6a4SAndroid Build Coastguard Worker                     if inject_irq {
315*bb4ee6a4SAndroid Build Coastguard Worker                         let _ = irq_evt.trigger();
316*bb4ee6a4SAndroid Build Coastguard Worker                     }
317*bb4ee6a4SAndroid Build Coastguard Worker                 }
318*bb4ee6a4SAndroid Build Coastguard Worker 
319*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Resample => {
320*bb4ee6a4SAndroid Build Coastguard Worker                     irq_evt.clear_resample();
321*bb4ee6a4SAndroid Build Coastguard Worker                     if state.lock().int_status() != 0 {
322*bb4ee6a4SAndroid Build Coastguard Worker                         let _ = irq_evt.trigger();
323*bb4ee6a4SAndroid Build Coastguard Worker                     }
324*bb4ee6a4SAndroid Build Coastguard Worker                 }
325*bb4ee6a4SAndroid Build Coastguard Worker 
326*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Kill => break 'poll,
327*bb4ee6a4SAndroid Build Coastguard Worker             }
328*bb4ee6a4SAndroid Build Coastguard Worker         }
329*bb4ee6a4SAndroid Build Coastguard Worker     }
330*bb4ee6a4SAndroid Build Coastguard Worker }
331*bb4ee6a4SAndroid Build Coastguard Worker 
332*bb4ee6a4SAndroid Build Coastguard Worker impl GoldfishBattery {
333*bb4ee6a4SAndroid Build Coastguard Worker     /// Create GoldfishBattery device model
334*bb4ee6a4SAndroid Build Coastguard Worker     ///
335*bb4ee6a4SAndroid Build Coastguard Worker     /// * `mmio_base` - The 32-bit mmio base address.
336*bb4ee6a4SAndroid Build Coastguard Worker     /// * `irq_num` - The corresponding interrupt number of the irq_evt which will be put into the
337*bb4ee6a4SAndroid Build Coastguard Worker     ///   ACPI DSDT.
338*bb4ee6a4SAndroid Build Coastguard Worker     /// * `irq_evt` - The interrupt event used to notify driver about the battery properties
339*bb4ee6a4SAndroid Build Coastguard Worker     ///   changing.
340*bb4ee6a4SAndroid Build Coastguard Worker     /// * `socket` - Battery control socket
new( mmio_base: u64, irq_num: u32, irq_evt: IrqLevelEvent, tube: Tube, create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>, create_powerd_client: Option<Box<dyn CreatePowerClientFn>>, ) -> Result<Self>341*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
342*bb4ee6a4SAndroid Build Coastguard Worker         mmio_base: u64,
343*bb4ee6a4SAndroid Build Coastguard Worker         irq_num: u32,
344*bb4ee6a4SAndroid Build Coastguard Worker         irq_evt: IrqLevelEvent,
345*bb4ee6a4SAndroid Build Coastguard Worker         tube: Tube,
346*bb4ee6a4SAndroid Build Coastguard Worker         create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
347*bb4ee6a4SAndroid Build Coastguard Worker         create_powerd_client: Option<Box<dyn CreatePowerClientFn>>,
348*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Self> {
349*bb4ee6a4SAndroid Build Coastguard Worker         if mmio_base + GOLDFISHBAT_MMIO_LEN - 1 > u32::MAX as u64 {
350*bb4ee6a4SAndroid Build Coastguard Worker             return Err(BatteryError::Non32BitMmioAddress);
351*bb4ee6a4SAndroid Build Coastguard Worker         }
352*bb4ee6a4SAndroid Build Coastguard Worker         let state = Arc::new(Mutex::new(GoldfishBatteryState {
353*bb4ee6a4SAndroid Build Coastguard Worker             capacity: 50,
354*bb4ee6a4SAndroid Build Coastguard Worker             health: BATTERY_HEALTH_VAL_UNKNOWN,
355*bb4ee6a4SAndroid Build Coastguard Worker             present: 1,
356*bb4ee6a4SAndroid Build Coastguard Worker             status: BATTERY_STATUS_VAL_UNKNOWN,
357*bb4ee6a4SAndroid Build Coastguard Worker             ac_online: 1,
358*bb4ee6a4SAndroid Build Coastguard Worker             int_enable: 0,
359*bb4ee6a4SAndroid Build Coastguard Worker             int_status: 0,
360*bb4ee6a4SAndroid Build Coastguard Worker             voltage: 0,
361*bb4ee6a4SAndroid Build Coastguard Worker             current: 0,
362*bb4ee6a4SAndroid Build Coastguard Worker             charge_counter: 0,
363*bb4ee6a4SAndroid Build Coastguard Worker             charge_full: 0,
364*bb4ee6a4SAndroid Build Coastguard Worker             initialized: false,
365*bb4ee6a4SAndroid Build Coastguard Worker         }));
366*bb4ee6a4SAndroid Build Coastguard Worker 
367*bb4ee6a4SAndroid Build Coastguard Worker         let battery_config = Arc::new(Mutex::new(BatConfig::default()));
368*bb4ee6a4SAndroid Build Coastguard Worker 
369*bb4ee6a4SAndroid Build Coastguard Worker         Ok(GoldfishBattery {
370*bb4ee6a4SAndroid Build Coastguard Worker             state,
371*bb4ee6a4SAndroid Build Coastguard Worker             mmio_base: mmio_base as u32,
372*bb4ee6a4SAndroid Build Coastguard Worker             irq_num,
373*bb4ee6a4SAndroid Build Coastguard Worker             irq_evt,
374*bb4ee6a4SAndroid Build Coastguard Worker             activated: false,
375*bb4ee6a4SAndroid Build Coastguard Worker             monitor_thread: None,
376*bb4ee6a4SAndroid Build Coastguard Worker             tube: Some(tube),
377*bb4ee6a4SAndroid Build Coastguard Worker             create_power_monitor,
378*bb4ee6a4SAndroid Build Coastguard Worker             create_powerd_client,
379*bb4ee6a4SAndroid Build Coastguard Worker             battery_config,
380*bb4ee6a4SAndroid Build Coastguard Worker         })
381*bb4ee6a4SAndroid Build Coastguard Worker     }
382*bb4ee6a4SAndroid Build Coastguard Worker 
383*bb4ee6a4SAndroid Build Coastguard Worker     /// return the descriptors used by this device
keep_rds(&self) -> Vec<RawDescriptor>384*bb4ee6a4SAndroid Build Coastguard Worker     pub fn keep_rds(&self) -> Vec<RawDescriptor> {
385*bb4ee6a4SAndroid Build Coastguard Worker         let mut rds = vec![
386*bb4ee6a4SAndroid Build Coastguard Worker             self.irq_evt.get_trigger().as_raw_descriptor(),
387*bb4ee6a4SAndroid Build Coastguard Worker             self.irq_evt.get_resample().as_raw_descriptor(),
388*bb4ee6a4SAndroid Build Coastguard Worker         ];
389*bb4ee6a4SAndroid Build Coastguard Worker 
390*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(tube) = &self.tube {
391*bb4ee6a4SAndroid Build Coastguard Worker             rds.push(tube.as_raw_descriptor());
392*bb4ee6a4SAndroid Build Coastguard Worker         }
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker         rds
395*bb4ee6a4SAndroid Build Coastguard Worker     }
396*bb4ee6a4SAndroid Build Coastguard Worker 
397*bb4ee6a4SAndroid Build Coastguard Worker     /// start a monitor thread to monitor the events from host
start_monitor(&mut self)398*bb4ee6a4SAndroid Build Coastguard Worker     fn start_monitor(&mut self) {
399*bb4ee6a4SAndroid Build Coastguard Worker         if self.activated {
400*bb4ee6a4SAndroid Build Coastguard Worker             return;
401*bb4ee6a4SAndroid Build Coastguard Worker         }
402*bb4ee6a4SAndroid Build Coastguard Worker 
403*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(tube) = self.tube.take() {
404*bb4ee6a4SAndroid Build Coastguard Worker             let irq_evt = self.irq_evt.try_clone().unwrap();
405*bb4ee6a4SAndroid Build Coastguard Worker             let bat_state = self.state.clone();
406*bb4ee6a4SAndroid Build Coastguard Worker             let create_monitor_fn = self.create_power_monitor.take();
407*bb4ee6a4SAndroid Build Coastguard Worker             let battery_config = self.battery_config.clone();
408*bb4ee6a4SAndroid Build Coastguard Worker             self.monitor_thread = Some(WorkerThread::start(self.debug_label(), move |kill_evt| {
409*bb4ee6a4SAndroid Build Coastguard Worker                 command_monitor(
410*bb4ee6a4SAndroid Build Coastguard Worker                     tube,
411*bb4ee6a4SAndroid Build Coastguard Worker                     irq_evt,
412*bb4ee6a4SAndroid Build Coastguard Worker                     kill_evt,
413*bb4ee6a4SAndroid Build Coastguard Worker                     bat_state,
414*bb4ee6a4SAndroid Build Coastguard Worker                     create_monitor_fn,
415*bb4ee6a4SAndroid Build Coastguard Worker                     battery_config,
416*bb4ee6a4SAndroid Build Coastguard Worker                 )
417*bb4ee6a4SAndroid Build Coastguard Worker             }));
418*bb4ee6a4SAndroid Build Coastguard Worker             self.activated = true;
419*bb4ee6a4SAndroid Build Coastguard Worker         }
420*bb4ee6a4SAndroid Build Coastguard Worker     }
421*bb4ee6a4SAndroid Build Coastguard Worker 
initialize_battery_state(&mut self) -> anyhow::Result<()>422*bb4ee6a4SAndroid Build Coastguard Worker     fn initialize_battery_state(&mut self) -> anyhow::Result<()> {
423*bb4ee6a4SAndroid Build Coastguard Worker         let mut power_client = match &self.create_powerd_client {
424*bb4ee6a4SAndroid Build Coastguard Worker             Some(f) => match f() {
425*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(c) => c,
426*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => bail!("failed to connect to the powerd: {:#}", e),
427*bb4ee6a4SAndroid Build Coastguard Worker             },
428*bb4ee6a4SAndroid Build Coastguard Worker             None => return Ok(()),
429*bb4ee6a4SAndroid Build Coastguard Worker         };
430*bb4ee6a4SAndroid Build Coastguard Worker         match power_client.get_power_data() {
431*bb4ee6a4SAndroid Build Coastguard Worker             Ok(data) => {
432*bb4ee6a4SAndroid Build Coastguard Worker                 let mut bat_state = self.state.lock();
433*bb4ee6a4SAndroid Build Coastguard Worker                 bat_state.set_ac_online(data.ac_online.into());
434*bb4ee6a4SAndroid Build Coastguard Worker 
435*bb4ee6a4SAndroid Build Coastguard Worker                 match data.battery {
436*bb4ee6a4SAndroid Build Coastguard Worker                     Some(battery_data) => {
437*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_capacity(battery_data.percent);
438*bb4ee6a4SAndroid Build Coastguard Worker                         let battery_status = match battery_data.status {
439*bb4ee6a4SAndroid Build Coastguard Worker                             BatteryStatus::Unknown => BATTERY_STATUS_VAL_UNKNOWN,
440*bb4ee6a4SAndroid Build Coastguard Worker                             BatteryStatus::Charging => BATTERY_STATUS_VAL_CHARGING,
441*bb4ee6a4SAndroid Build Coastguard Worker                             BatteryStatus::Discharging => BATTERY_STATUS_VAL_DISCHARGING,
442*bb4ee6a4SAndroid Build Coastguard Worker                             BatteryStatus::NotCharging => BATTERY_STATUS_VAL_NOT_CHARGING,
443*bb4ee6a4SAndroid Build Coastguard Worker                         };
444*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_status(battery_status);
445*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_voltage(battery_data.voltage);
446*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_current(battery_data.current);
447*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_charge_counter(battery_data.charge_counter);
448*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_charge_full(battery_data.charge_full);
449*bb4ee6a4SAndroid Build Coastguard Worker                     }
450*bb4ee6a4SAndroid Build Coastguard Worker                     None => {
451*bb4ee6a4SAndroid Build Coastguard Worker                         bat_state.set_present(0);
452*bb4ee6a4SAndroid Build Coastguard Worker                     }
453*bb4ee6a4SAndroid Build Coastguard Worker                 }
454*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(())
455*bb4ee6a4SAndroid Build Coastguard Worker             }
456*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
457*bb4ee6a4SAndroid Build Coastguard Worker                 bail!("failed to get response from powerd: {:#}", e);
458*bb4ee6a4SAndroid Build Coastguard Worker             }
459*bb4ee6a4SAndroid Build Coastguard Worker         }
460*bb4ee6a4SAndroid Build Coastguard Worker     }
461*bb4ee6a4SAndroid Build Coastguard Worker }
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for GoldfishBattery {
drop(&mut self)464*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
465*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = self.sleep() {
466*bb4ee6a4SAndroid Build Coastguard Worker             error!("{}", e);
467*bb4ee6a4SAndroid Build Coastguard Worker         };
468*bb4ee6a4SAndroid Build Coastguard Worker     }
469*bb4ee6a4SAndroid Build Coastguard Worker }
470*bb4ee6a4SAndroid Build Coastguard Worker 
471*bb4ee6a4SAndroid Build Coastguard Worker impl BusDevice for GoldfishBattery {
device_id(&self) -> DeviceId472*bb4ee6a4SAndroid Build Coastguard Worker     fn device_id(&self) -> DeviceId {
473*bb4ee6a4SAndroid Build Coastguard Worker         CrosvmDeviceId::GoldfishBattery.into()
474*bb4ee6a4SAndroid Build Coastguard Worker     }
475*bb4ee6a4SAndroid Build Coastguard Worker 
debug_label(&self) -> String476*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> String {
477*bb4ee6a4SAndroid Build Coastguard Worker         "GoldfishBattery".to_owned()
478*bb4ee6a4SAndroid Build Coastguard Worker     }
479*bb4ee6a4SAndroid Build Coastguard Worker 
read(&mut self, info: BusAccessInfo, data: &mut [u8])480*bb4ee6a4SAndroid Build Coastguard Worker     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
481*bb4ee6a4SAndroid Build Coastguard Worker         if data.len() != std::mem::size_of::<u32>() {
482*bb4ee6a4SAndroid Build Coastguard Worker             warn!(
483*bb4ee6a4SAndroid Build Coastguard Worker                 "{}: unsupported read length {}, only support 4bytes read",
484*bb4ee6a4SAndroid Build Coastguard Worker                 self.debug_label(),
485*bb4ee6a4SAndroid Build Coastguard Worker                 data.len()
486*bb4ee6a4SAndroid Build Coastguard Worker             );
487*bb4ee6a4SAndroid Build Coastguard Worker             return;
488*bb4ee6a4SAndroid Build Coastguard Worker         }
489*bb4ee6a4SAndroid Build Coastguard Worker 
490*bb4ee6a4SAndroid Build Coastguard Worker         // Before first read, we try to ask powerd the actual power data to initialize `self.state`.
491*bb4ee6a4SAndroid Build Coastguard Worker         if !self.state.lock().initialized {
492*bb4ee6a4SAndroid Build Coastguard Worker             match self.initialize_battery_state() {
493*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(()) => self.state.lock().initialized = true,
494*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
495*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
496*bb4ee6a4SAndroid Build Coastguard Worker                         "{}: failed to get power data and update: {:#}",
497*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
498*bb4ee6a4SAndroid Build Coastguard Worker                         e
499*bb4ee6a4SAndroid Build Coastguard Worker                     );
500*bb4ee6a4SAndroid Build Coastguard Worker                 }
501*bb4ee6a4SAndroid Build Coastguard Worker             }
502*bb4ee6a4SAndroid Build Coastguard Worker         }
503*bb4ee6a4SAndroid Build Coastguard Worker 
504*bb4ee6a4SAndroid Build Coastguard Worker         let val = match info.offset as u32 {
505*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_INT_STATUS => {
506*bb4ee6a4SAndroid Build Coastguard Worker                 // read to clear the interrupt status
507*bb4ee6a4SAndroid Build Coastguard Worker                 std::mem::replace(&mut self.state.lock().int_status, 0)
508*bb4ee6a4SAndroid Build Coastguard Worker             }
509*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_INT_ENABLE => self.state.lock().int_enable,
510*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_AC_ONLINE => match *self.battery_config.lock() {
511*bb4ee6a4SAndroid Build Coastguard Worker                 BatConfig::Real => self.state.lock().ac_online,
512*bb4ee6a4SAndroid Build Coastguard Worker                 BatConfig::Fake { max_capacity: _ } => AC_ONLINE_VAL_OFFLINE,
513*bb4ee6a4SAndroid Build Coastguard Worker             },
514*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_STATUS => match *self.battery_config.lock() {
515*bb4ee6a4SAndroid Build Coastguard Worker                 BatConfig::Real => self.state.lock().status,
516*bb4ee6a4SAndroid Build Coastguard Worker                 BatConfig::Fake { max_capacity: _ } => BATTERY_STATUS_VAL_DISCHARGING,
517*bb4ee6a4SAndroid Build Coastguard Worker             },
518*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_HEALTH => self.state.lock().health,
519*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_PRESENT => self.state.lock().present,
520*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CAPACITY => {
521*bb4ee6a4SAndroid Build Coastguard Worker                 let max_capacity = match *self.battery_config.lock() {
522*bb4ee6a4SAndroid Build Coastguard Worker                     BatConfig::Real => 100,
523*bb4ee6a4SAndroid Build Coastguard Worker                     BatConfig::Fake { max_capacity } => max_capacity,
524*bb4ee6a4SAndroid Build Coastguard Worker                 };
525*bb4ee6a4SAndroid Build Coastguard Worker                 std::cmp::min(max_capacity, self.state.lock().capacity)
526*bb4ee6a4SAndroid Build Coastguard Worker             }
527*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_VOLTAGE => self.state.lock().voltage,
528*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_TEMP => 0,
529*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CHARGE_COUNTER => self.state.lock().charge_counter,
530*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_VOLTAGE_MAX => 0,
531*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CURRENT_MAX => 0,
532*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CURRENT_NOW => self.state.lock().current,
533*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CURRENT_AVG => 0,
534*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CHARGE_FULL_UAH => self.state.lock().charge_full,
535*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_CYCLE_COUNT => 0,
536*bb4ee6a4SAndroid Build Coastguard Worker             _ => {
537*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("{}: unsupported read address {}", self.debug_label(), info);
538*bb4ee6a4SAndroid Build Coastguard Worker                 return;
539*bb4ee6a4SAndroid Build Coastguard Worker             }
540*bb4ee6a4SAndroid Build Coastguard Worker         };
541*bb4ee6a4SAndroid Build Coastguard Worker 
542*bb4ee6a4SAndroid Build Coastguard Worker         let val_arr = val.to_ne_bytes();
543*bb4ee6a4SAndroid Build Coastguard Worker         data.copy_from_slice(&val_arr);
544*bb4ee6a4SAndroid Build Coastguard Worker     }
545*bb4ee6a4SAndroid Build Coastguard Worker 
write(&mut self, info: BusAccessInfo, data: &[u8])546*bb4ee6a4SAndroid Build Coastguard Worker     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
547*bb4ee6a4SAndroid Build Coastguard Worker         if data.len() != std::mem::size_of::<u32>() {
548*bb4ee6a4SAndroid Build Coastguard Worker             warn!(
549*bb4ee6a4SAndroid Build Coastguard Worker                 "{}: unsupported write length {}, only support 4bytes write",
550*bb4ee6a4SAndroid Build Coastguard Worker                 self.debug_label(),
551*bb4ee6a4SAndroid Build Coastguard Worker                 data.len()
552*bb4ee6a4SAndroid Build Coastguard Worker             );
553*bb4ee6a4SAndroid Build Coastguard Worker             return;
554*bb4ee6a4SAndroid Build Coastguard Worker         }
555*bb4ee6a4SAndroid Build Coastguard Worker 
556*bb4ee6a4SAndroid Build Coastguard Worker         let mut val_arr = u32::to_ne_bytes(0u32);
557*bb4ee6a4SAndroid Build Coastguard Worker         val_arr.copy_from_slice(data);
558*bb4ee6a4SAndroid Build Coastguard Worker         let val = u32::from_ne_bytes(val_arr);
559*bb4ee6a4SAndroid Build Coastguard Worker 
560*bb4ee6a4SAndroid Build Coastguard Worker         match info.offset as u32 {
561*bb4ee6a4SAndroid Build Coastguard Worker             BATTERY_INT_ENABLE => {
562*bb4ee6a4SAndroid Build Coastguard Worker                 self.state.lock().int_enable = val;
563*bb4ee6a4SAndroid Build Coastguard Worker                 if (val & BATTERY_INT_MASK) != 0 && !self.activated {
564*bb4ee6a4SAndroid Build Coastguard Worker                     self.start_monitor();
565*bb4ee6a4SAndroid Build Coastguard Worker                 }
566*bb4ee6a4SAndroid Build Coastguard Worker             }
567*bb4ee6a4SAndroid Build Coastguard Worker             _ => {
568*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("{}: Bad write to address {}", self.debug_label(), info);
569*bb4ee6a4SAndroid Build Coastguard Worker             }
570*bb4ee6a4SAndroid Build Coastguard Worker         };
571*bb4ee6a4SAndroid Build Coastguard Worker     }
572*bb4ee6a4SAndroid Build Coastguard Worker }
573*bb4ee6a4SAndroid Build Coastguard Worker 
574*bb4ee6a4SAndroid Build Coastguard Worker impl Aml for GoldfishBattery {
to_aml_bytes(&self, bytes: &mut Vec<u8>)575*bb4ee6a4SAndroid Build Coastguard Worker     fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
576*bb4ee6a4SAndroid Build Coastguard Worker         aml::Device::new(
577*bb4ee6a4SAndroid Build Coastguard Worker             "GFBY".into(),
578*bb4ee6a4SAndroid Build Coastguard Worker             vec![
579*bb4ee6a4SAndroid Build Coastguard Worker                 &aml::Name::new("_HID".into(), &"GFSH0001"),
580*bb4ee6a4SAndroid Build Coastguard Worker                 &aml::Name::new(
581*bb4ee6a4SAndroid Build Coastguard Worker                     "_CRS".into(),
582*bb4ee6a4SAndroid Build Coastguard Worker                     &aml::ResourceTemplate::new(vec![
583*bb4ee6a4SAndroid Build Coastguard Worker                         &aml::Memory32Fixed::new(true, self.mmio_base, GOLDFISHBAT_MMIO_LEN as u32),
584*bb4ee6a4SAndroid Build Coastguard Worker                         &aml::Interrupt::new(true, false, false, true, self.irq_num),
585*bb4ee6a4SAndroid Build Coastguard Worker                     ]),
586*bb4ee6a4SAndroid Build Coastguard Worker                 ),
587*bb4ee6a4SAndroid Build Coastguard Worker             ],
588*bb4ee6a4SAndroid Build Coastguard Worker         )
589*bb4ee6a4SAndroid Build Coastguard Worker         .to_aml_bytes(bytes);
590*bb4ee6a4SAndroid Build Coastguard Worker     }
591*bb4ee6a4SAndroid Build Coastguard Worker }
592*bb4ee6a4SAndroid Build Coastguard Worker 
593*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for GoldfishBattery {
sleep(&mut self) -> anyhow::Result<()>594*bb4ee6a4SAndroid Build Coastguard Worker     fn sleep(&mut self) -> anyhow::Result<()> {
595*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(thread) = self.monitor_thread.take() {
596*bb4ee6a4SAndroid Build Coastguard Worker             thread.stop();
597*bb4ee6a4SAndroid Build Coastguard Worker         }
598*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
599*bb4ee6a4SAndroid Build Coastguard Worker     }
600*bb4ee6a4SAndroid Build Coastguard Worker 
wake(&mut self) -> anyhow::Result<()>601*bb4ee6a4SAndroid Build Coastguard Worker     fn wake(&mut self) -> anyhow::Result<()> {
602*bb4ee6a4SAndroid Build Coastguard Worker         if self.activated {
603*bb4ee6a4SAndroid Build Coastguard Worker             // Set activated to false for start_monitor to start monitoring again.
604*bb4ee6a4SAndroid Build Coastguard Worker             self.activated = false;
605*bb4ee6a4SAndroid Build Coastguard Worker             self.start_monitor();
606*bb4ee6a4SAndroid Build Coastguard Worker         }
607*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
608*bb4ee6a4SAndroid Build Coastguard Worker     }
609*bb4ee6a4SAndroid Build Coastguard Worker 
snapshot(&mut self) -> anyhow::Result<serde_json::Value>610*bb4ee6a4SAndroid Build Coastguard Worker     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
611*bb4ee6a4SAndroid Build Coastguard Worker         serde_json::to_value(GoldfishBatterySnapshot {
612*bb4ee6a4SAndroid Build Coastguard Worker             state: self.state.lock().clone(),
613*bb4ee6a4SAndroid Build Coastguard Worker             mmio_base: self.mmio_base,
614*bb4ee6a4SAndroid Build Coastguard Worker             irq_num: self.irq_num,
615*bb4ee6a4SAndroid Build Coastguard Worker             activated: self.activated,
616*bb4ee6a4SAndroid Build Coastguard Worker         })
617*bb4ee6a4SAndroid Build Coastguard Worker         .context("failed to snapshot GoldfishBattery")
618*bb4ee6a4SAndroid Build Coastguard Worker     }
619*bb4ee6a4SAndroid Build Coastguard Worker 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>620*bb4ee6a4SAndroid Build Coastguard Worker     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
621*bb4ee6a4SAndroid Build Coastguard Worker         let deser: GoldfishBatterySnapshot =
622*bb4ee6a4SAndroid Build Coastguard Worker             serde_json::from_value(data).context("failed to deserialize GoldfishBattery")?;
623*bb4ee6a4SAndroid Build Coastguard Worker         {
624*bb4ee6a4SAndroid Build Coastguard Worker             let mut locked_state = self.state.lock();
625*bb4ee6a4SAndroid Build Coastguard Worker             *locked_state = deser.state;
626*bb4ee6a4SAndroid Build Coastguard Worker         }
627*bb4ee6a4SAndroid Build Coastguard Worker         self.mmio_base = deser.mmio_base;
628*bb4ee6a4SAndroid Build Coastguard Worker         self.irq_num = deser.irq_num;
629*bb4ee6a4SAndroid Build Coastguard Worker         self.activated = deser.activated;
630*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
631*bb4ee6a4SAndroid Build Coastguard Worker     }
632*bb4ee6a4SAndroid Build Coastguard Worker }
633*bb4ee6a4SAndroid Build Coastguard Worker 
634*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
635*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
636*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
637*bb4ee6a4SAndroid Build Coastguard Worker     use crate::suspendable_tests;
638*bb4ee6a4SAndroid Build Coastguard Worker 
modify_device(battery: &mut GoldfishBattery)639*bb4ee6a4SAndroid Build Coastguard Worker     fn modify_device(battery: &mut GoldfishBattery) {
640*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = battery.state.lock();
641*bb4ee6a4SAndroid Build Coastguard Worker         state.set_capacity(70);
642*bb4ee6a4SAndroid Build Coastguard Worker     }
643*bb4ee6a4SAndroid Build Coastguard Worker 
644*bb4ee6a4SAndroid Build Coastguard Worker     suspendable_tests! {
645*bb4ee6a4SAndroid Build Coastguard Worker         battery, GoldfishBattery::new(
646*bb4ee6a4SAndroid Build Coastguard Worker             0,
647*bb4ee6a4SAndroid Build Coastguard Worker             0,
648*bb4ee6a4SAndroid Build Coastguard Worker             IrqLevelEvent::new().unwrap(),
649*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().unwrap().1,
650*bb4ee6a4SAndroid Build Coastguard Worker             None,
651*bb4ee6a4SAndroid Build Coastguard Worker             None,
652*bb4ee6a4SAndroid Build Coastguard Worker         ).unwrap(),
653*bb4ee6a4SAndroid Build Coastguard Worker         modify_device
654*bb4ee6a4SAndroid Build Coastguard Worker     }
655*bb4ee6a4SAndroid Build Coastguard Worker }
656