xref: /aosp_15_r20/external/crosvm/devices/src/cmos.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 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::cmp::min;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant;
9*bb4ee6a4SAndroid Build Coastguard Worker 
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
11*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::custom_serde::deserialize_seq_to_arr;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::custom_serde::serialize_arr;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::Timer;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::TimerTrait;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
23*bb4ee6a4SAndroid Build Coastguard Worker use chrono::DateTime;
24*bb4ee6a4SAndroid Build Coastguard Worker use chrono::Datelike;
25*bb4ee6a4SAndroid Build Coastguard Worker use chrono::TimeZone;
26*bb4ee6a4SAndroid Build Coastguard Worker use chrono::Timelike;
27*bb4ee6a4SAndroid Build Coastguard Worker use chrono::Utc;
28*bb4ee6a4SAndroid Build Coastguard Worker use metrics::log_metric;
29*bb4ee6a4SAndroid Build Coastguard Worker use metrics::MetricEventType;
30*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
31*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
32*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
33*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmResponse;
34*bb4ee6a4SAndroid Build Coastguard Worker 
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::CrosvmDeviceId;
36*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusAccessInfo;
37*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusDevice;
38*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceId;
39*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqEdgeEvent;
40*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker pub const RTC_IRQ: u8 = 8;
43*bb4ee6a4SAndroid Build Coastguard Worker 
44*bb4ee6a4SAndroid Build Coastguard Worker const INDEX_MASK: u8 = 0x7f;
45*bb4ee6a4SAndroid Build Coastguard Worker const INDEX_OFFSET: u64 = 0x0;
46*bb4ee6a4SAndroid Build Coastguard Worker const DATA_OFFSET: u64 = 0x1;
47*bb4ee6a4SAndroid Build Coastguard Worker const DATA_LEN: usize = 128;
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_SEC: u8 = 0x0;
50*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_ALARM_SEC: u8 = 0x1;
51*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_MIN: u8 = 0x2;
52*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_ALARM_MIN: u8 = 0x3;
53*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_HOUR: u8 = 0x4;
54*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_ALARM_HOUR: u8 = 0x5;
55*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_WEEK_DAY: u8 = 0x6;
56*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_DAY: u8 = 0x7;
57*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_MONTH: u8 = 0x8;
58*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_YEAR: u8 = 0x9;
59*bb4ee6a4SAndroid Build Coastguard Worker pub const RTC_REG_CENTURY: u8 = 0x32;
60*bb4ee6a4SAndroid Build Coastguard Worker pub const RTC_REG_ALARM_DAY: u8 = 0x33;
61*bb4ee6a4SAndroid Build Coastguard Worker pub const RTC_REG_ALARM_MONTH: u8 = 0x34;
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_B: u8 = 0x0b;
64*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_B_UNSUPPORTED: u8 = 0xdd;
65*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_B_24_HOUR_MODE: u8 = 0x02;
66*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_B_ALARM_ENABLE: u8 = 0x20;
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_C: u8 = 0x0c;
69*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_C_IRQF: u8 = 0x80;
70*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_C_AF: u8 = 0x20;
71*bb4ee6a4SAndroid Build Coastguard Worker 
72*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_D: u8 = 0x0d;
73*bb4ee6a4SAndroid Build Coastguard Worker const RTC_REG_D_VRT: u8 = 0x80; // RAM and time valid
74*bb4ee6a4SAndroid Build Coastguard Worker 
75*bb4ee6a4SAndroid Build Coastguard Worker pub type CmosNowFn = fn() -> DateTime<Utc>;
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker // Alarm state shared between Cmos and the alarm worker thread.
78*bb4ee6a4SAndroid Build Coastguard Worker struct AlarmState {
79*bb4ee6a4SAndroid Build Coastguard Worker     alarm: Timer,
80*bb4ee6a4SAndroid Build Coastguard Worker     vm_control: Tube,
81*bb4ee6a4SAndroid Build Coastguard Worker     irq: IrqEdgeEvent,
82*bb4ee6a4SAndroid Build Coastguard Worker     armed_time: Instant,
83*bb4ee6a4SAndroid Build Coastguard Worker     clear_evt: Option<Event>,
84*bb4ee6a4SAndroid Build Coastguard Worker }
85*bb4ee6a4SAndroid Build Coastguard Worker 
86*bb4ee6a4SAndroid Build Coastguard Worker impl AlarmState {
trigger_rtc_interrupt(&self) -> anyhow::Result<Event>87*bb4ee6a4SAndroid Build Coastguard Worker     fn trigger_rtc_interrupt(&self) -> anyhow::Result<Event> {
88*bb4ee6a4SAndroid Build Coastguard Worker         self.irq.trigger().context("failed to trigger irq")?;
89*bb4ee6a4SAndroid Build Coastguard Worker 
90*bb4ee6a4SAndroid Build Coastguard Worker         let elapsed = self.armed_time.elapsed().as_millis();
91*bb4ee6a4SAndroid Build Coastguard Worker         log_metric(
92*bb4ee6a4SAndroid Build Coastguard Worker             MetricEventType::RtcWakeup,
93*bb4ee6a4SAndroid Build Coastguard Worker             elapsed.try_into().unwrap_or(i64::MAX),
94*bb4ee6a4SAndroid Build Coastguard Worker         );
95*bb4ee6a4SAndroid Build Coastguard Worker 
96*bb4ee6a4SAndroid Build Coastguard Worker         let msg = vm_control::VmRequest::Rtc {
97*bb4ee6a4SAndroid Build Coastguard Worker             clear_evt: Event::new().context("failed to create clear event")?,
98*bb4ee6a4SAndroid Build Coastguard Worker         };
99*bb4ee6a4SAndroid Build Coastguard Worker 
100*bb4ee6a4SAndroid Build Coastguard Worker         // The Linux kernel expects wakeups to come via ACPI when ACPI is enabled. There's
101*bb4ee6a4SAndroid Build Coastguard Worker         // no real way to determine that here, so just send this unconditionally.
102*bb4ee6a4SAndroid Build Coastguard Worker         self.vm_control.send(&msg).context("send failed")?;
103*bb4ee6a4SAndroid Build Coastguard Worker 
104*bb4ee6a4SAndroid Build Coastguard Worker         let vm_control::VmRequest::Rtc { clear_evt } = msg else {
105*bb4ee6a4SAndroid Build Coastguard Worker             unreachable!("message type failure");
106*bb4ee6a4SAndroid Build Coastguard Worker         };
107*bb4ee6a4SAndroid Build Coastguard Worker 
108*bb4ee6a4SAndroid Build Coastguard Worker         match self.vm_control.recv().context("recv failed")? {
109*bb4ee6a4SAndroid Build Coastguard Worker             VmResponse::Ok => Ok(clear_evt),
110*bb4ee6a4SAndroid Build Coastguard Worker             resp => Err(anyhow!("unexpected rtc response: {:?}", resp)),
111*bb4ee6a4SAndroid Build Coastguard Worker         }
112*bb4ee6a4SAndroid Build Coastguard Worker     }
113*bb4ee6a4SAndroid Build Coastguard Worker }
114*bb4ee6a4SAndroid Build Coastguard Worker 
115*bb4ee6a4SAndroid Build Coastguard Worker /// A CMOS/RTC device commonly seen on x86 I/O port 0x70/0x71.
116*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize)]
117*bb4ee6a4SAndroid Build Coastguard Worker pub struct Cmos {
118*bb4ee6a4SAndroid Build Coastguard Worker     index: u8,
119*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(serialize_with = "serialize_arr")]
120*bb4ee6a4SAndroid Build Coastguard Worker     data: [u8; DATA_LEN],
121*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(skip_serializing)] // skip serializing time function.
122*bb4ee6a4SAndroid Build Coastguard Worker     now_fn: CmosNowFn,
123*bb4ee6a4SAndroid Build Coastguard Worker     // alarm_time is re-loaded from data on deserialization, so there's
124*bb4ee6a4SAndroid Build Coastguard Worker     // no need to explicitly serialize it.
125*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(skip_serializing)]
126*bb4ee6a4SAndroid Build Coastguard Worker     alarm_time: Option<DateTime<Utc>>,
127*bb4ee6a4SAndroid Build Coastguard Worker     // alarm_state fields are either constant across snapshotting or
128*bb4ee6a4SAndroid Build Coastguard Worker     // reloaded from |data| on restore, so no need to serialize.
129*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(skip_serializing)]
130*bb4ee6a4SAndroid Build Coastguard Worker     alarm_state: Arc<Mutex<AlarmState>>,
131*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(skip_serializing)] // skip serializing the worker thread
132*bb4ee6a4SAndroid Build Coastguard Worker     worker: Option<WorkerThread<()>>,
133*bb4ee6a4SAndroid Build Coastguard Worker }
134*bb4ee6a4SAndroid Build Coastguard Worker 
135*bb4ee6a4SAndroid Build Coastguard Worker impl Cmos {
136*bb4ee6a4SAndroid Build Coastguard Worker     /// Constructs a CMOS/RTC device with initial data.
137*bb4ee6a4SAndroid Build Coastguard Worker     /// `mem_below_4g` is the size of memory in bytes below the 32-bit gap.
138*bb4ee6a4SAndroid Build Coastguard Worker     /// `mem_above_4g` is the size of memory in bytes above the 32-bit gap.
139*bb4ee6a4SAndroid Build Coastguard Worker     /// `now_fn` is a function that returns the current date and time.
new( mem_below_4g: u64, mem_above_4g: u64, now_fn: CmosNowFn, vm_control: Tube, irq: IrqEdgeEvent, ) -> anyhow::Result<Cmos>140*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
141*bb4ee6a4SAndroid Build Coastguard Worker         mem_below_4g: u64,
142*bb4ee6a4SAndroid Build Coastguard Worker         mem_above_4g: u64,
143*bb4ee6a4SAndroid Build Coastguard Worker         now_fn: CmosNowFn,
144*bb4ee6a4SAndroid Build Coastguard Worker         vm_control: Tube,
145*bb4ee6a4SAndroid Build Coastguard Worker         irq: IrqEdgeEvent,
146*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<Cmos> {
147*bb4ee6a4SAndroid Build Coastguard Worker         let mut data = [0u8; DATA_LEN];
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker         data[0x0B] = RTC_REG_B_24_HOUR_MODE; // Status Register B: 24-hour mode
150*bb4ee6a4SAndroid Build Coastguard Worker 
151*bb4ee6a4SAndroid Build Coastguard Worker         // Extended memory from 16 MB to 4 GB in units of 64 KB
152*bb4ee6a4SAndroid Build Coastguard Worker         let ext_mem = min(
153*bb4ee6a4SAndroid Build Coastguard Worker             0xFFFF,
154*bb4ee6a4SAndroid Build Coastguard Worker             mem_below_4g.saturating_sub(16 * 1024 * 1024) / (64 * 1024),
155*bb4ee6a4SAndroid Build Coastguard Worker         );
156*bb4ee6a4SAndroid Build Coastguard Worker         data[0x34] = ext_mem as u8;
157*bb4ee6a4SAndroid Build Coastguard Worker         data[0x35] = (ext_mem >> 8) as u8;
158*bb4ee6a4SAndroid Build Coastguard Worker 
159*bb4ee6a4SAndroid Build Coastguard Worker         // High memory (> 4GB) in units of 64 KB
160*bb4ee6a4SAndroid Build Coastguard Worker         let high_mem = min(0xFFFFFF, mem_above_4g / (64 * 1024));
161*bb4ee6a4SAndroid Build Coastguard Worker         data[0x5b] = high_mem as u8;
162*bb4ee6a4SAndroid Build Coastguard Worker         data[0x5c] = (high_mem >> 8) as u8;
163*bb4ee6a4SAndroid Build Coastguard Worker         data[0x5d] = (high_mem >> 16) as u8;
164*bb4ee6a4SAndroid Build Coastguard Worker 
165*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Cmos {
166*bb4ee6a4SAndroid Build Coastguard Worker             index: 0,
167*bb4ee6a4SAndroid Build Coastguard Worker             data,
168*bb4ee6a4SAndroid Build Coastguard Worker             now_fn,
169*bb4ee6a4SAndroid Build Coastguard Worker             alarm_time: None,
170*bb4ee6a4SAndroid Build Coastguard Worker             alarm_state: Arc::new(Mutex::new(AlarmState {
171*bb4ee6a4SAndroid Build Coastguard Worker                 alarm: Timer::new().context("cmos timer")?,
172*bb4ee6a4SAndroid Build Coastguard Worker                 irq,
173*bb4ee6a4SAndroid Build Coastguard Worker                 vm_control,
174*bb4ee6a4SAndroid Build Coastguard Worker                 // Not actually armed, but simpler than wrapping with an Option.
175*bb4ee6a4SAndroid Build Coastguard Worker                 armed_time: Instant::now(),
176*bb4ee6a4SAndroid Build Coastguard Worker                 clear_evt: None,
177*bb4ee6a4SAndroid Build Coastguard Worker             })),
178*bb4ee6a4SAndroid Build Coastguard Worker             worker: None,
179*bb4ee6a4SAndroid Build Coastguard Worker         })
180*bb4ee6a4SAndroid Build Coastguard Worker     }
181*bb4ee6a4SAndroid Build Coastguard Worker 
spawn_worker(&mut self, alarm_state: Arc<Mutex<AlarmState>>)182*bb4ee6a4SAndroid Build Coastguard Worker     fn spawn_worker(&mut self, alarm_state: Arc<Mutex<AlarmState>>) {
183*bb4ee6a4SAndroid Build Coastguard Worker         self.worker = Some(WorkerThread::start("CMOS_alarm", move |kill_evt| {
184*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = run_cmos_worker(alarm_state, kill_evt) {
185*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Failed to spawn worker {:?}", e);
186*bb4ee6a4SAndroid Build Coastguard Worker             }
187*bb4ee6a4SAndroid Build Coastguard Worker         }));
188*bb4ee6a4SAndroid Build Coastguard Worker     }
189*bb4ee6a4SAndroid Build Coastguard Worker 
set_alarm(&mut self)190*bb4ee6a4SAndroid Build Coastguard Worker     fn set_alarm(&mut self) {
191*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = self.alarm_state.lock();
192*bb4ee6a4SAndroid Build Coastguard Worker         if self.data[RTC_REG_B as usize] & RTC_REG_B_ALARM_ENABLE != 0 {
193*bb4ee6a4SAndroid Build Coastguard Worker             let now = (self.now_fn)();
194*bb4ee6a4SAndroid Build Coastguard Worker             let target = alarm_from_registers(now.year(), &self.data).and_then(|this_year| {
195*bb4ee6a4SAndroid Build Coastguard Worker                 // There is no year register for the alarm. If the alarm target has
196*bb4ee6a4SAndroid Build Coastguard Worker                 // already passed this year, then the next time it will occur is next
197*bb4ee6a4SAndroid Build Coastguard Worker                 // year.
198*bb4ee6a4SAndroid Build Coastguard Worker                 //
199*bb4ee6a4SAndroid Build Coastguard Worker                 // Note that there is something of a race condition here. If |now|
200*bb4ee6a4SAndroid Build Coastguard Worker                 // advances while the driver is configuring the alarm, then an alarm that
201*bb4ee6a4SAndroid Build Coastguard Worker                 // should only be one second in the future could become one year in the
202*bb4ee6a4SAndroid Build Coastguard Worker                 // future. Unfortunately there isn't anything in the rtc-cmos hardware
203*bb4ee6a4SAndroid Build Coastguard Worker                 // specification that lets us handle this race condition in the device, so
204*bb4ee6a4SAndroid Build Coastguard Worker                 // we just have to rely on the driver to deal with it.
205*bb4ee6a4SAndroid Build Coastguard Worker                 if this_year < now {
206*bb4ee6a4SAndroid Build Coastguard Worker                     alarm_from_registers(now.year() + 1, &self.data)
207*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
208*bb4ee6a4SAndroid Build Coastguard Worker                     Some(this_year)
209*bb4ee6a4SAndroid Build Coastguard Worker                 }
210*bb4ee6a4SAndroid Build Coastguard Worker             });
211*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(target) = target {
212*bb4ee6a4SAndroid Build Coastguard Worker                 if Some(target) != self.alarm_time {
213*bb4ee6a4SAndroid Build Coastguard Worker                     self.alarm_time = Some(target);
214*bb4ee6a4SAndroid Build Coastguard Worker                     state.armed_time = Instant::now();
215*bb4ee6a4SAndroid Build Coastguard Worker 
216*bb4ee6a4SAndroid Build Coastguard Worker                     let duration = target
217*bb4ee6a4SAndroid Build Coastguard Worker                         .signed_duration_since(now)
218*bb4ee6a4SAndroid Build Coastguard Worker                         .to_std()
219*bb4ee6a4SAndroid Build Coastguard Worker                         .unwrap_or(Duration::new(0, 0));
220*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = state.alarm.reset_oneshot(duration) {
221*bb4ee6a4SAndroid Build Coastguard Worker                         error!("Failed to set alarm {:?}", e);
222*bb4ee6a4SAndroid Build Coastguard Worker                     }
223*bb4ee6a4SAndroid Build Coastguard Worker                 }
224*bb4ee6a4SAndroid Build Coastguard Worker             }
225*bb4ee6a4SAndroid Build Coastguard Worker         } else if self.alarm_time.take().is_some() {
226*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = state.alarm.clear() {
227*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Failed to clear alarm {:?}", e);
228*bb4ee6a4SAndroid Build Coastguard Worker             }
229*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(clear_evt) = state.clear_evt.take() {
230*bb4ee6a4SAndroid Build Coastguard Worker                 if let Err(e) = clear_evt.signal() {
231*bb4ee6a4SAndroid Build Coastguard Worker                     error!("failed to clear rtc pm signal {:?}", e);
232*bb4ee6a4SAndroid Build Coastguard Worker                 }
233*bb4ee6a4SAndroid Build Coastguard Worker             }
234*bb4ee6a4SAndroid Build Coastguard Worker         }
235*bb4ee6a4SAndroid Build Coastguard Worker 
236*bb4ee6a4SAndroid Build Coastguard Worker         let needs_worker = self.alarm_time.is_some();
237*bb4ee6a4SAndroid Build Coastguard Worker         drop(state);
238*bb4ee6a4SAndroid Build Coastguard Worker 
239*bb4ee6a4SAndroid Build Coastguard Worker         if needs_worker && self.worker.is_none() {
240*bb4ee6a4SAndroid Build Coastguard Worker             self.spawn_worker(self.alarm_state.clone());
241*bb4ee6a4SAndroid Build Coastguard Worker         }
242*bb4ee6a4SAndroid Build Coastguard Worker     }
243*bb4ee6a4SAndroid Build Coastguard Worker }
244*bb4ee6a4SAndroid Build Coastguard Worker 
run_cmos_worker(alarm_state: Arc<Mutex<AlarmState>>, kill_evt: Event) -> anyhow::Result<()>245*bb4ee6a4SAndroid Build Coastguard Worker fn run_cmos_worker(alarm_state: Arc<Mutex<AlarmState>>, kill_evt: Event) -> anyhow::Result<()> {
246*bb4ee6a4SAndroid Build Coastguard Worker     #[derive(EventToken)]
247*bb4ee6a4SAndroid Build Coastguard Worker     enum Token {
248*bb4ee6a4SAndroid Build Coastguard Worker         Alarm,
249*bb4ee6a4SAndroid Build Coastguard Worker         Kill,
250*bb4ee6a4SAndroid Build Coastguard Worker     }
251*bb4ee6a4SAndroid Build Coastguard Worker 
252*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
253*bb4ee6a4SAndroid Build Coastguard Worker         (&alarm_state.lock().alarm, Token::Alarm),
254*bb4ee6a4SAndroid Build Coastguard Worker         (&kill_evt, Token::Kill),
255*bb4ee6a4SAndroid Build Coastguard Worker     ])
256*bb4ee6a4SAndroid Build Coastguard Worker     .context("worker context failed")?;
257*bb4ee6a4SAndroid Build Coastguard Worker 
258*bb4ee6a4SAndroid Build Coastguard Worker     loop {
259*bb4ee6a4SAndroid Build Coastguard Worker         let events = wait_ctx.wait().context("wait failed")?;
260*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = alarm_state.lock();
261*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
262*bb4ee6a4SAndroid Build Coastguard Worker             match event.token {
263*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Alarm => {
264*bb4ee6a4SAndroid Build Coastguard Worker                     if state.alarm.mark_waited().context("timer ack failed")? {
265*bb4ee6a4SAndroid Build Coastguard Worker                         continue;
266*bb4ee6a4SAndroid Build Coastguard Worker                     }
267*bb4ee6a4SAndroid Build Coastguard Worker 
268*bb4ee6a4SAndroid Build Coastguard Worker                     match state.trigger_rtc_interrupt() {
269*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(clear_evt) => state.clear_evt = Some(clear_evt),
270*bb4ee6a4SAndroid Build Coastguard Worker                         Err(e) => error!("Failed to send rtc {:?}", e),
271*bb4ee6a4SAndroid Build Coastguard Worker                     }
272*bb4ee6a4SAndroid Build Coastguard Worker                 }
273*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Kill => return Ok(()),
274*bb4ee6a4SAndroid Build Coastguard Worker             }
275*bb4ee6a4SAndroid Build Coastguard Worker         }
276*bb4ee6a4SAndroid Build Coastguard Worker     }
277*bb4ee6a4SAndroid Build Coastguard Worker }
278*bb4ee6a4SAndroid Build Coastguard Worker 
from_bcd(v: u8) -> Option<u32>279*bb4ee6a4SAndroid Build Coastguard Worker fn from_bcd(v: u8) -> Option<u32> {
280*bb4ee6a4SAndroid Build Coastguard Worker     let ones = (v & 0xf) as u32;
281*bb4ee6a4SAndroid Build Coastguard Worker     let tens = (v >> 4) as u32;
282*bb4ee6a4SAndroid Build Coastguard Worker     if ones < 10 && tens < 10 {
283*bb4ee6a4SAndroid Build Coastguard Worker         Some(10 * tens + ones)
284*bb4ee6a4SAndroid Build Coastguard Worker     } else {
285*bb4ee6a4SAndroid Build Coastguard Worker         None
286*bb4ee6a4SAndroid Build Coastguard Worker     }
287*bb4ee6a4SAndroid Build Coastguard Worker }
288*bb4ee6a4SAndroid Build Coastguard Worker 
alarm_from_registers(year: i32, data: &[u8; DATA_LEN]) -> Option<DateTime<Utc>>289*bb4ee6a4SAndroid Build Coastguard Worker fn alarm_from_registers(year: i32, data: &[u8; DATA_LEN]) -> Option<DateTime<Utc>> {
290*bb4ee6a4SAndroid Build Coastguard Worker     Utc.with_ymd_and_hms(
291*bb4ee6a4SAndroid Build Coastguard Worker         year,
292*bb4ee6a4SAndroid Build Coastguard Worker         from_bcd(data[RTC_REG_ALARM_MONTH as usize])?,
293*bb4ee6a4SAndroid Build Coastguard Worker         from_bcd(data[RTC_REG_ALARM_DAY as usize])?,
294*bb4ee6a4SAndroid Build Coastguard Worker         from_bcd(data[RTC_REG_ALARM_HOUR as usize])?,
295*bb4ee6a4SAndroid Build Coastguard Worker         from_bcd(data[RTC_REG_ALARM_MIN as usize])?,
296*bb4ee6a4SAndroid Build Coastguard Worker         from_bcd(data[RTC_REG_ALARM_SEC as usize])?,
297*bb4ee6a4SAndroid Build Coastguard Worker     )
298*bb4ee6a4SAndroid Build Coastguard Worker     .single()
299*bb4ee6a4SAndroid Build Coastguard Worker }
300*bb4ee6a4SAndroid Build Coastguard Worker 
301*bb4ee6a4SAndroid Build Coastguard Worker impl BusDevice for Cmos {
device_id(&self) -> DeviceId302*bb4ee6a4SAndroid Build Coastguard Worker     fn device_id(&self) -> DeviceId {
303*bb4ee6a4SAndroid Build Coastguard Worker         CrosvmDeviceId::Cmos.into()
304*bb4ee6a4SAndroid Build Coastguard Worker     }
305*bb4ee6a4SAndroid Build Coastguard Worker 
debug_label(&self) -> String306*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> String {
307*bb4ee6a4SAndroid Build Coastguard Worker         "cmos".to_owned()
308*bb4ee6a4SAndroid Build Coastguard Worker     }
309*bb4ee6a4SAndroid Build Coastguard Worker 
write(&mut self, info: BusAccessInfo, data: &[u8])310*bb4ee6a4SAndroid Build Coastguard Worker     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
311*bb4ee6a4SAndroid Build Coastguard Worker         if data.len() != 1 {
312*bb4ee6a4SAndroid Build Coastguard Worker             return;
313*bb4ee6a4SAndroid Build Coastguard Worker         }
314*bb4ee6a4SAndroid Build Coastguard Worker 
315*bb4ee6a4SAndroid Build Coastguard Worker         match info.offset {
316*bb4ee6a4SAndroid Build Coastguard Worker             INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
317*bb4ee6a4SAndroid Build Coastguard Worker             DATA_OFFSET => {
318*bb4ee6a4SAndroid Build Coastguard Worker                 let mut data = data[0];
319*bb4ee6a4SAndroid Build Coastguard Worker                 if self.index == RTC_REG_B {
320*bb4ee6a4SAndroid Build Coastguard Worker                     // The features which we don't support are:
321*bb4ee6a4SAndroid Build Coastguard Worker                     //   0x80 (SET)  - disable clock updates (i.e. let guest configure the clock)
322*bb4ee6a4SAndroid Build Coastguard Worker                     //   0x40 (PIE)  - enable periodic interrupts
323*bb4ee6a4SAndroid Build Coastguard Worker                     //   0x10 (IUE)  - enable interrupts after clock updates
324*bb4ee6a4SAndroid Build Coastguard Worker                     //   0x08 (SQWE) - enable square wave generation
325*bb4ee6a4SAndroid Build Coastguard Worker                     //   0x04 (DM)   - use binary data format (instead of BCD)
326*bb4ee6a4SAndroid Build Coastguard Worker                     //   0x01 (DSE)  - control daylight savings (we just do what the host does)
327*bb4ee6a4SAndroid Build Coastguard Worker                     if data & RTC_REG_B_UNSUPPORTED != 0 {
328*bb4ee6a4SAndroid Build Coastguard Worker                         info!(
329*bb4ee6a4SAndroid Build Coastguard Worker                             "Ignoring unsupported bits: {:x}",
330*bb4ee6a4SAndroid Build Coastguard Worker                             data & RTC_REG_B_UNSUPPORTED
331*bb4ee6a4SAndroid Build Coastguard Worker                         );
332*bb4ee6a4SAndroid Build Coastguard Worker                         data &= !RTC_REG_B_UNSUPPORTED;
333*bb4ee6a4SAndroid Build Coastguard Worker                     }
334*bb4ee6a4SAndroid Build Coastguard Worker                     if data & RTC_REG_B_24_HOUR_MODE == 0 {
335*bb4ee6a4SAndroid Build Coastguard Worker                         info!("12-hour mode unsupported");
336*bb4ee6a4SAndroid Build Coastguard Worker                         data |= RTC_REG_B_24_HOUR_MODE;
337*bb4ee6a4SAndroid Build Coastguard Worker                     }
338*bb4ee6a4SAndroid Build Coastguard Worker                 }
339*bb4ee6a4SAndroid Build Coastguard Worker 
340*bb4ee6a4SAndroid Build Coastguard Worker                 self.data[self.index as usize] = data;
341*bb4ee6a4SAndroid Build Coastguard Worker 
342*bb4ee6a4SAndroid Build Coastguard Worker                 if self.index == RTC_REG_B {
343*bb4ee6a4SAndroid Build Coastguard Worker                     self.set_alarm();
344*bb4ee6a4SAndroid Build Coastguard Worker                 }
345*bb4ee6a4SAndroid Build Coastguard Worker             }
346*bb4ee6a4SAndroid Build Coastguard Worker             o => panic!("bad write offset on CMOS device: {}", o),
347*bb4ee6a4SAndroid Build Coastguard Worker         }
348*bb4ee6a4SAndroid Build Coastguard Worker     }
349*bb4ee6a4SAndroid Build Coastguard Worker 
read(&mut self, info: BusAccessInfo, data: &mut [u8])350*bb4ee6a4SAndroid Build Coastguard Worker     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
351*bb4ee6a4SAndroid Build Coastguard Worker         fn to_bcd(v: u8) -> u8 {
352*bb4ee6a4SAndroid Build Coastguard Worker             assert!(v < 100);
353*bb4ee6a4SAndroid Build Coastguard Worker             ((v / 10) << 4) | (v % 10)
354*bb4ee6a4SAndroid Build Coastguard Worker         }
355*bb4ee6a4SAndroid Build Coastguard Worker 
356*bb4ee6a4SAndroid Build Coastguard Worker         if data.len() != 1 {
357*bb4ee6a4SAndroid Build Coastguard Worker             return;
358*bb4ee6a4SAndroid Build Coastguard Worker         }
359*bb4ee6a4SAndroid Build Coastguard Worker 
360*bb4ee6a4SAndroid Build Coastguard Worker         data[0] = match info.offset {
361*bb4ee6a4SAndroid Build Coastguard Worker             INDEX_OFFSET => self.index,
362*bb4ee6a4SAndroid Build Coastguard Worker             DATA_OFFSET => {
363*bb4ee6a4SAndroid Build Coastguard Worker                 let now = (self.now_fn)();
364*bb4ee6a4SAndroid Build Coastguard Worker                 let seconds = now.second(); // 0..=59
365*bb4ee6a4SAndroid Build Coastguard Worker                 let minutes = now.minute(); // 0..=59
366*bb4ee6a4SAndroid Build Coastguard Worker                 let hours = now.hour(); // 0..=23 (24-hour mode only)
367*bb4ee6a4SAndroid Build Coastguard Worker                 let week_day = now.weekday().number_from_sunday(); // 1 (Sun) ..= 7 (Sat)
368*bb4ee6a4SAndroid Build Coastguard Worker                 let day = now.day(); // 1..=31
369*bb4ee6a4SAndroid Build Coastguard Worker                 let month = now.month(); // 1..=12
370*bb4ee6a4SAndroid Build Coastguard Worker                 let year = now.year();
371*bb4ee6a4SAndroid Build Coastguard Worker                 match self.index {
372*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_SEC => to_bcd(seconds as u8),
373*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_MIN => to_bcd(minutes as u8),
374*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_HOUR => to_bcd(hours as u8),
375*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_WEEK_DAY => to_bcd(week_day as u8),
376*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_DAY => to_bcd(day as u8),
377*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_MONTH => to_bcd(month as u8),
378*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_YEAR => to_bcd((year % 100) as u8),
379*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_CENTURY => to_bcd((year / 100) as u8),
380*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_C => {
381*bb4ee6a4SAndroid Build Coastguard Worker                         if self
382*bb4ee6a4SAndroid Build Coastguard Worker                             .alarm_time
383*bb4ee6a4SAndroid Build Coastguard Worker                             .map_or(false, |alarm_time| alarm_time <= now)
384*bb4ee6a4SAndroid Build Coastguard Worker                         {
385*bb4ee6a4SAndroid Build Coastguard Worker                             // Reading from RTC_REG_C resets interrupts, so clear the
386*bb4ee6a4SAndroid Build Coastguard Worker                             // status bits. The IrqEdgeEvent is reset automatically.
387*bb4ee6a4SAndroid Build Coastguard Worker                             self.alarm_time.take();
388*bb4ee6a4SAndroid Build Coastguard Worker                             RTC_REG_C_IRQF | RTC_REG_C_AF
389*bb4ee6a4SAndroid Build Coastguard Worker                         } else {
390*bb4ee6a4SAndroid Build Coastguard Worker                             0
391*bb4ee6a4SAndroid Build Coastguard Worker                         }
392*bb4ee6a4SAndroid Build Coastguard Worker                     }
393*bb4ee6a4SAndroid Build Coastguard Worker                     RTC_REG_D => RTC_REG_D_VRT,
394*bb4ee6a4SAndroid Build Coastguard Worker                     _ => {
395*bb4ee6a4SAndroid Build Coastguard Worker                         // self.index is always guaranteed to be in range via INDEX_MASK.
396*bb4ee6a4SAndroid Build Coastguard Worker                         self.data[(self.index & INDEX_MASK) as usize]
397*bb4ee6a4SAndroid Build Coastguard Worker                     }
398*bb4ee6a4SAndroid Build Coastguard Worker                 }
399*bb4ee6a4SAndroid Build Coastguard Worker             }
400*bb4ee6a4SAndroid Build Coastguard Worker             o => panic!("bad read offset on CMOS device: {}", o),
401*bb4ee6a4SAndroid Build Coastguard Worker         }
402*bb4ee6a4SAndroid Build Coastguard Worker     }
403*bb4ee6a4SAndroid Build Coastguard Worker }
404*bb4ee6a4SAndroid Build Coastguard Worker 
405*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for Cmos {
snapshot(&mut self) -> anyhow::Result<serde_json::Value>406*bb4ee6a4SAndroid Build Coastguard Worker     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
407*bb4ee6a4SAndroid Build Coastguard Worker         serde_json::to_value(self).context("failed to serialize Cmos")
408*bb4ee6a4SAndroid Build Coastguard Worker     }
409*bb4ee6a4SAndroid Build Coastguard Worker 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>410*bb4ee6a4SAndroid Build Coastguard Worker     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
411*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(Deserialize)]
412*bb4ee6a4SAndroid Build Coastguard Worker         struct CmosIndex {
413*bb4ee6a4SAndroid Build Coastguard Worker             index: u8,
414*bb4ee6a4SAndroid Build Coastguard Worker             #[serde(deserialize_with = "deserialize_seq_to_arr")]
415*bb4ee6a4SAndroid Build Coastguard Worker             data: [u8; DATA_LEN],
416*bb4ee6a4SAndroid Build Coastguard Worker         }
417*bb4ee6a4SAndroid Build Coastguard Worker 
418*bb4ee6a4SAndroid Build Coastguard Worker         let deser: CmosIndex =
419*bb4ee6a4SAndroid Build Coastguard Worker             serde_json::from_value(data).context("failed to deserialize Cmos")?;
420*bb4ee6a4SAndroid Build Coastguard Worker         self.index = deser.index;
421*bb4ee6a4SAndroid Build Coastguard Worker         self.data = deser.data;
422*bb4ee6a4SAndroid Build Coastguard Worker         self.set_alarm();
423*bb4ee6a4SAndroid Build Coastguard Worker 
424*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
425*bb4ee6a4SAndroid Build Coastguard Worker     }
426*bb4ee6a4SAndroid Build Coastguard Worker 
sleep(&mut self) -> anyhow::Result<()>427*bb4ee6a4SAndroid Build Coastguard Worker     fn sleep(&mut self) -> anyhow::Result<()> {
428*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(worker) = self.worker.take() {
429*bb4ee6a4SAndroid Build Coastguard Worker             worker.stop();
430*bb4ee6a4SAndroid Build Coastguard Worker         }
431*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
432*bb4ee6a4SAndroid Build Coastguard Worker     }
433*bb4ee6a4SAndroid Build Coastguard Worker 
wake(&mut self) -> anyhow::Result<()>434*bb4ee6a4SAndroid Build Coastguard Worker     fn wake(&mut self) -> anyhow::Result<()> {
435*bb4ee6a4SAndroid Build Coastguard Worker         self.spawn_worker(self.alarm_state.clone());
436*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
437*bb4ee6a4SAndroid Build Coastguard Worker     }
438*bb4ee6a4SAndroid Build Coastguard Worker }
439*bb4ee6a4SAndroid Build Coastguard Worker 
440*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
441*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
442*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
443*bb4ee6a4SAndroid Build Coastguard Worker     use crate::suspendable_tests;
444*bb4ee6a4SAndroid Build Coastguard Worker 
read_reg(cmos: &mut Cmos, reg: u8) -> u8445*bb4ee6a4SAndroid Build Coastguard Worker     fn read_reg(cmos: &mut Cmos, reg: u8) -> u8 {
446*bb4ee6a4SAndroid Build Coastguard Worker         // Write register number to INDEX_OFFSET (0).
447*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(
448*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
449*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 0,
450*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x70,
451*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
452*bb4ee6a4SAndroid Build Coastguard Worker             },
453*bb4ee6a4SAndroid Build Coastguard Worker             &[reg],
454*bb4ee6a4SAndroid Build Coastguard Worker         );
455*bb4ee6a4SAndroid Build Coastguard Worker 
456*bb4ee6a4SAndroid Build Coastguard Worker         // Read register value back from DATA_OFFSET (1).
457*bb4ee6a4SAndroid Build Coastguard Worker 
458*bb4ee6a4SAndroid Build Coastguard Worker         let mut data = [0u8];
459*bb4ee6a4SAndroid Build Coastguard Worker         cmos.read(
460*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
461*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 1,
462*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x71,
463*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
464*bb4ee6a4SAndroid Build Coastguard Worker             },
465*bb4ee6a4SAndroid Build Coastguard Worker             &mut data,
466*bb4ee6a4SAndroid Build Coastguard Worker         );
467*bb4ee6a4SAndroid Build Coastguard Worker         data[0]
468*bb4ee6a4SAndroid Build Coastguard Worker     }
469*bb4ee6a4SAndroid Build Coastguard Worker 
write_reg(cmos: &mut Cmos, reg: u8, val: u8)470*bb4ee6a4SAndroid Build Coastguard Worker     fn write_reg(cmos: &mut Cmos, reg: u8, val: u8) {
471*bb4ee6a4SAndroid Build Coastguard Worker         // Write register number to INDEX_OFFSET (0).
472*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(
473*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
474*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 0,
475*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x70,
476*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
477*bb4ee6a4SAndroid Build Coastguard Worker             },
478*bb4ee6a4SAndroid Build Coastguard Worker             &[reg],
479*bb4ee6a4SAndroid Build Coastguard Worker         );
480*bb4ee6a4SAndroid Build Coastguard Worker 
481*bb4ee6a4SAndroid Build Coastguard Worker         // Write register value to DATA_OFFSET (1).
482*bb4ee6a4SAndroid Build Coastguard Worker 
483*bb4ee6a4SAndroid Build Coastguard Worker         let data = [val];
484*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(
485*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
486*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 1,
487*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x71,
488*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
489*bb4ee6a4SAndroid Build Coastguard Worker             },
490*bb4ee6a4SAndroid Build Coastguard Worker             &data,
491*bb4ee6a4SAndroid Build Coastguard Worker         );
492*bb4ee6a4SAndroid Build Coastguard Worker     }
493*bb4ee6a4SAndroid Build Coastguard Worker 
timestamp_to_datetime(timestamp: i64) -> DateTime<Utc>494*bb4ee6a4SAndroid Build Coastguard Worker     fn timestamp_to_datetime(timestamp: i64) -> DateTime<Utc> {
495*bb4ee6a4SAndroid Build Coastguard Worker         DateTime::from_timestamp(timestamp, 0).unwrap()
496*bb4ee6a4SAndroid Build Coastguard Worker     }
497*bb4ee6a4SAndroid Build Coastguard Worker 
test_now_party_like_its_1999() -> DateTime<Utc>498*bb4ee6a4SAndroid Build Coastguard Worker     fn test_now_party_like_its_1999() -> DateTime<Utc> {
499*bb4ee6a4SAndroid Build Coastguard Worker         // 1999-12-31T23:59:59+00:00
500*bb4ee6a4SAndroid Build Coastguard Worker         timestamp_to_datetime(946684799)
501*bb4ee6a4SAndroid Build Coastguard Worker     }
502*bb4ee6a4SAndroid Build Coastguard Worker 
test_now_y2k_compliant() -> DateTime<Utc>503*bb4ee6a4SAndroid Build Coastguard Worker     fn test_now_y2k_compliant() -> DateTime<Utc> {
504*bb4ee6a4SAndroid Build Coastguard Worker         // 2000-01-01T00:00:00+00:00
505*bb4ee6a4SAndroid Build Coastguard Worker         timestamp_to_datetime(946684800)
506*bb4ee6a4SAndroid Build Coastguard Worker     }
507*bb4ee6a4SAndroid Build Coastguard Worker 
test_now_2016_before_leap_second() -> DateTime<Utc>508*bb4ee6a4SAndroid Build Coastguard Worker     fn test_now_2016_before_leap_second() -> DateTime<Utc> {
509*bb4ee6a4SAndroid Build Coastguard Worker         // 2016-12-31T23:59:59+00:00
510*bb4ee6a4SAndroid Build Coastguard Worker         timestamp_to_datetime(1483228799)
511*bb4ee6a4SAndroid Build Coastguard Worker     }
512*bb4ee6a4SAndroid Build Coastguard Worker 
test_now_2017_after_leap_second() -> DateTime<Utc>513*bb4ee6a4SAndroid Build Coastguard Worker     fn test_now_2017_after_leap_second() -> DateTime<Utc> {
514*bb4ee6a4SAndroid Build Coastguard Worker         // 2017-01-01T00:00:00+00:00
515*bb4ee6a4SAndroid Build Coastguard Worker         timestamp_to_datetime(1483228800)
516*bb4ee6a4SAndroid Build Coastguard Worker     }
517*bb4ee6a4SAndroid Build Coastguard Worker 
new_cmos_for_test(now_fn: CmosNowFn) -> Cmos518*bb4ee6a4SAndroid Build Coastguard Worker     fn new_cmos_for_test(now_fn: CmosNowFn) -> Cmos {
519*bb4ee6a4SAndroid Build Coastguard Worker         let irq = IrqEdgeEvent::new().unwrap();
520*bb4ee6a4SAndroid Build Coastguard Worker         Cmos::new(1024, 0, now_fn, Tube::pair().unwrap().0, irq).unwrap()
521*bb4ee6a4SAndroid Build Coastguard Worker     }
522*bb4ee6a4SAndroid Build Coastguard Worker 
523*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_write_index()524*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_write_index() {
525*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
526*bb4ee6a4SAndroid Build Coastguard Worker         // Write index.
527*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(
528*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
529*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 0,
530*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x71,
531*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
532*bb4ee6a4SAndroid Build Coastguard Worker             },
533*bb4ee6a4SAndroid Build Coastguard Worker             &[0x41],
534*bb4ee6a4SAndroid Build Coastguard Worker         );
535*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.index, 0x41);
536*bb4ee6a4SAndroid Build Coastguard Worker     }
537*bb4ee6a4SAndroid Build Coastguard Worker 
538*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_write_data()539*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_write_data() {
540*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
541*bb4ee6a4SAndroid Build Coastguard Worker         // Write data 0x01 at index 0x41.
542*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(
543*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
544*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 0,
545*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x71,
546*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
547*bb4ee6a4SAndroid Build Coastguard Worker             },
548*bb4ee6a4SAndroid Build Coastguard Worker             &[0x41],
549*bb4ee6a4SAndroid Build Coastguard Worker         );
550*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(
551*bb4ee6a4SAndroid Build Coastguard Worker             BusAccessInfo {
552*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 1,
553*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x71,
554*bb4ee6a4SAndroid Build Coastguard Worker                 id: 0,
555*bb4ee6a4SAndroid Build Coastguard Worker             },
556*bb4ee6a4SAndroid Build Coastguard Worker             &[0x01],
557*bb4ee6a4SAndroid Build Coastguard Worker         );
558*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.data[0x41], 0x01);
559*bb4ee6a4SAndroid Build Coastguard Worker     }
560*bb4ee6a4SAndroid Build Coastguard Worker 
modify_device(cmos: &mut Cmos)561*bb4ee6a4SAndroid Build Coastguard Worker     fn modify_device(cmos: &mut Cmos) {
562*bb4ee6a4SAndroid Build Coastguard Worker         let info_index = BusAccessInfo {
563*bb4ee6a4SAndroid Build Coastguard Worker             offset: 0,
564*bb4ee6a4SAndroid Build Coastguard Worker             address: 0x71,
565*bb4ee6a4SAndroid Build Coastguard Worker             id: 0,
566*bb4ee6a4SAndroid Build Coastguard Worker         };
567*bb4ee6a4SAndroid Build Coastguard Worker 
568*bb4ee6a4SAndroid Build Coastguard Worker         let info_data = BusAccessInfo {
569*bb4ee6a4SAndroid Build Coastguard Worker             offset: 1,
570*bb4ee6a4SAndroid Build Coastguard Worker             address: 0x71,
571*bb4ee6a4SAndroid Build Coastguard Worker             id: 0,
572*bb4ee6a4SAndroid Build Coastguard Worker         };
573*bb4ee6a4SAndroid Build Coastguard Worker         // change index to 0x42.
574*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(info_index, &[0x42]);
575*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(info_data, &[0x01]);
576*bb4ee6a4SAndroid Build Coastguard Worker     }
577*bb4ee6a4SAndroid Build Coastguard Worker 
578*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_date_time_1999()579*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_date_time_1999() {
580*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
581*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x00), 0x59); // seconds
582*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x02), 0x59); // minutes
583*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x04), 0x23); // hours
584*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x06), 0x06); // day of week
585*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x07), 0x31); // day of month
586*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x08), 0x12); // month
587*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x09), 0x99); // year
588*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x32), 0x19); // century
589*bb4ee6a4SAndroid Build Coastguard Worker     }
590*bb4ee6a4SAndroid Build Coastguard Worker 
591*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_date_time_2000()592*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_date_time_2000() {
593*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_y2k_compliant);
594*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x00), 0x00); // seconds
595*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x02), 0x00); // minutes
596*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x04), 0x00); // hours
597*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x06), 0x07); // day of week
598*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x07), 0x01); // day of month
599*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x08), 0x01); // month
600*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x09), 0x00); // year
601*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
602*bb4ee6a4SAndroid Build Coastguard Worker     }
603*bb4ee6a4SAndroid Build Coastguard Worker 
604*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_date_time_before_leap_second()605*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_date_time_before_leap_second() {
606*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_2016_before_leap_second);
607*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x00), 0x59); // seconds
608*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x02), 0x59); // minutes
609*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x04), 0x23); // hours
610*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x06), 0x07); // day of week
611*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x07), 0x31); // day of month
612*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x08), 0x12); // month
613*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x09), 0x16); // year
614*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
615*bb4ee6a4SAndroid Build Coastguard Worker     }
616*bb4ee6a4SAndroid Build Coastguard Worker 
617*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_date_time_after_leap_second()618*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_date_time_after_leap_second() {
619*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_2017_after_leap_second);
620*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x00), 0x00); // seconds
621*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x02), 0x00); // minutes
622*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x04), 0x00); // hours
623*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x06), 0x01); // day of week
624*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x07), 0x01); // day of month
625*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x08), 0x01); // month
626*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x09), 0x17); // year
627*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
628*bb4ee6a4SAndroid Build Coastguard Worker     }
629*bb4ee6a4SAndroid Build Coastguard Worker 
630*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_alarm()631*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_alarm() {
632*bb4ee6a4SAndroid Build Coastguard Worker         // 2000-01-02T03:04:05+00:00
633*bb4ee6a4SAndroid Build Coastguard Worker         let now_fn = || timestamp_to_datetime(946782245);
634*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(now_fn);
635*bb4ee6a4SAndroid Build Coastguard Worker 
636*bb4ee6a4SAndroid Build Coastguard Worker         // A date later this year
637*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x01, 0x06); // seconds
638*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x03, 0x05); // minutes
639*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x05, 0x04); // hours
640*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x33, 0x03); // day of month
641*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x34, 0x02); // month
642*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
643*bb4ee6a4SAndroid Build Coastguard Worker                                           // 2000-02-03T04:05:06+00:00
644*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(949550706)));
645*bb4ee6a4SAndroid Build Coastguard Worker 
646*bb4ee6a4SAndroid Build Coastguard Worker         // A date (one year - one second) in the future
647*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x01, 0x04); // seconds
648*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x03, 0x04); // minutes
649*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x05, 0x03); // hours
650*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x33, 0x02); // day of month
651*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x34, 0x01); // month
652*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
653*bb4ee6a4SAndroid Build Coastguard Worker                                           // 2001-01-02T03:04:04+00:00
654*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(978404644)));
655*bb4ee6a4SAndroid Build Coastguard Worker 
656*bb4ee6a4SAndroid Build Coastguard Worker         // The current time
657*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x01, 0x05); // seconds
658*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x03, 0x04); // minutes
659*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x05, 0x03); // hours
660*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x33, 0x02); // day of month
661*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x34, 0x01); // month
662*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
663*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(946782245)));
664*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x0c), 0xa0); // RTC_REG_C_IRQF | RTC_REG_C_AF
665*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.alarm_time, None);
666*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x0c), 0);
667*bb4ee6a4SAndroid Build Coastguard Worker 
668*bb4ee6a4SAndroid Build Coastguard Worker         // Invalid BCD
669*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x01, 0xa0); // seconds
670*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
671*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.alarm_time, None);
672*bb4ee6a4SAndroid Build Coastguard Worker     }
673*bb4ee6a4SAndroid Build Coastguard Worker 
674*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_reg_d()675*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_reg_d() {
676*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
677*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(read_reg(&mut cmos, 0x0d), 0x80) // RAM and time are valid
678*bb4ee6a4SAndroid Build Coastguard Worker     }
679*bb4ee6a4SAndroid Build Coastguard Worker 
680*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_snapshot_restore() -> anyhow::Result<()>681*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_snapshot_restore() -> anyhow::Result<()> {
682*bb4ee6a4SAndroid Build Coastguard Worker         // time function doesn't matter in this case.
683*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
684*bb4ee6a4SAndroid Build Coastguard Worker 
685*bb4ee6a4SAndroid Build Coastguard Worker         let info_index = BusAccessInfo {
686*bb4ee6a4SAndroid Build Coastguard Worker             offset: 0,
687*bb4ee6a4SAndroid Build Coastguard Worker             address: 0x71,
688*bb4ee6a4SAndroid Build Coastguard Worker             id: 0,
689*bb4ee6a4SAndroid Build Coastguard Worker         };
690*bb4ee6a4SAndroid Build Coastguard Worker 
691*bb4ee6a4SAndroid Build Coastguard Worker         let info_data = BusAccessInfo {
692*bb4ee6a4SAndroid Build Coastguard Worker             offset: 1,
693*bb4ee6a4SAndroid Build Coastguard Worker             address: 0x71,
694*bb4ee6a4SAndroid Build Coastguard Worker             id: 0,
695*bb4ee6a4SAndroid Build Coastguard Worker         };
696*bb4ee6a4SAndroid Build Coastguard Worker 
697*bb4ee6a4SAndroid Build Coastguard Worker         // change index to 0x41.
698*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(info_index, &[0x41]);
699*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(info_data, &[0x01]);
700*bb4ee6a4SAndroid Build Coastguard Worker 
701*bb4ee6a4SAndroid Build Coastguard Worker         let snap = cmos.snapshot().context("failed to snapshot Cmos")?;
702*bb4ee6a4SAndroid Build Coastguard Worker 
703*bb4ee6a4SAndroid Build Coastguard Worker         // change index to 0x42.
704*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(info_index, &[0x42]);
705*bb4ee6a4SAndroid Build Coastguard Worker         cmos.write(info_data, &[0x01]);
706*bb4ee6a4SAndroid Build Coastguard Worker 
707*bb4ee6a4SAndroid Build Coastguard Worker         // Restore Cmos.
708*bb4ee6a4SAndroid Build Coastguard Worker         cmos.restore(snap).context("failed to restore Cmos")?;
709*bb4ee6a4SAndroid Build Coastguard Worker 
710*bb4ee6a4SAndroid Build Coastguard Worker         // after restore, the index should be 0x41, which was the index before snapshot was taken.
711*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.index, 0x41);
712*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.data[0x41], 0x01);
713*bb4ee6a4SAndroid Build Coastguard Worker         assert_ne!(cmos.data[0x42], 0x01);
714*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
715*bb4ee6a4SAndroid Build Coastguard Worker     }
716*bb4ee6a4SAndroid Build Coastguard Worker 
717*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
cmos_sleep_wake()718*bb4ee6a4SAndroid Build Coastguard Worker     fn cmos_sleep_wake() {
719*bb4ee6a4SAndroid Build Coastguard Worker         // 2000-01-02T03:04:05+00:00
720*bb4ee6a4SAndroid Build Coastguard Worker         let irq = IrqEdgeEvent::new().unwrap();
721*bb4ee6a4SAndroid Build Coastguard Worker         let now_fn = || timestamp_to_datetime(946782245);
722*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmos = Cmos::new(1024, 0, now_fn, Tube::pair().unwrap().0, irq).unwrap();
723*bb4ee6a4SAndroid Build Coastguard Worker 
724*bb4ee6a4SAndroid Build Coastguard Worker         // A date later this year
725*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x01, 0x06); // seconds
726*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x03, 0x05); // minutes
727*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x05, 0x04); // hours
728*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x33, 0x03); // day of month
729*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x34, 0x02); // month
730*bb4ee6a4SAndroid Build Coastguard Worker         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
731*bb4ee6a4SAndroid Build Coastguard Worker                                           // 2000-02-03T04:05:06+00:00
732*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(949550706)));
733*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmos.worker.is_some());
734*bb4ee6a4SAndroid Build Coastguard Worker 
735*bb4ee6a4SAndroid Build Coastguard Worker         cmos.sleep().unwrap();
736*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmos.worker.is_none());
737*bb4ee6a4SAndroid Build Coastguard Worker 
738*bb4ee6a4SAndroid Build Coastguard Worker         cmos.wake().unwrap();
739*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmos.worker.is_some());
740*bb4ee6a4SAndroid Build Coastguard Worker     }
741*bb4ee6a4SAndroid Build Coastguard Worker 
742*bb4ee6a4SAndroid Build Coastguard Worker     suspendable_tests!(
743*bb4ee6a4SAndroid Build Coastguard Worker         cmos1999,
744*bb4ee6a4SAndroid Build Coastguard Worker         new_cmos_for_test(test_now_party_like_its_1999),
745*bb4ee6a4SAndroid Build Coastguard Worker         modify_device
746*bb4ee6a4SAndroid Build Coastguard Worker     );
747*bb4ee6a4SAndroid Build Coastguard Worker     suspendable_tests!(
748*bb4ee6a4SAndroid Build Coastguard Worker         cmos2k,
749*bb4ee6a4SAndroid Build Coastguard Worker         new_cmos_for_test(test_now_y2k_compliant),
750*bb4ee6a4SAndroid Build Coastguard Worker         modify_device
751*bb4ee6a4SAndroid Build Coastguard Worker     );
752*bb4ee6a4SAndroid Build Coastguard Worker     suspendable_tests!(
753*bb4ee6a4SAndroid Build Coastguard Worker         cmos2016,
754*bb4ee6a4SAndroid Build Coastguard Worker         new_cmos_for_test(test_now_2016_before_leap_second),
755*bb4ee6a4SAndroid Build Coastguard Worker         modify_device
756*bb4ee6a4SAndroid Build Coastguard Worker     );
757*bb4ee6a4SAndroid Build Coastguard Worker     suspendable_tests!(
758*bb4ee6a4SAndroid Build Coastguard Worker         cmos2017,
759*bb4ee6a4SAndroid Build Coastguard Worker         new_cmos_for_test(test_now_2017_after_leap_second),
760*bb4ee6a4SAndroid Build Coastguard Worker         modify_device
761*bb4ee6a4SAndroid Build Coastguard Worker     );
762*bb4ee6a4SAndroid Build Coastguard Worker }
763