devices/
i8042.rs

1// Copyright 2017 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use base::error;
6use base::SendTube;
7use base::VmEventType;
8use snapshot::AnySnapshot;
9
10use crate::pci::CrosvmDeviceId;
11use crate::BusAccessInfo;
12use crate::BusDevice;
13use crate::DeviceId;
14use crate::Suspendable;
15
16/// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
17pub struct I8042Device {
18    reset_evt_wrtube: SendTube,
19}
20
21impl I8042Device {
22    /// Constructs a i8042 device that will signal the given event when the guest requests it.
23    pub fn new(reset_evt_wrtube: SendTube) -> I8042Device {
24        I8042Device { reset_evt_wrtube }
25    }
26}
27
28// i8042 device is mapped I/O address 0x61. We partially implement two 8-bit
29// registers: port 0x61 (I8042_PORT_B_REG), and port 0x64 (I8042_COMMAND_REG).
30impl BusDevice for I8042Device {
31    fn device_id(&self) -> DeviceId {
32        CrosvmDeviceId::I8042.into()
33    }
34
35    fn debug_label(&self) -> String {
36        "i8042".to_owned()
37    }
38
39    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
40        if data.len() == 1 && info.address == 0x64 {
41            data[0] = 0x0;
42        } else if data.len() == 1 && info.address == 0x61 {
43            // Like kvmtool, we return bit 5 set in I8042_PORT_B_REG to
44            // avoid hang in pit_calibrate_tsc() in Linux kernel.
45            data[0] = 0x20;
46        }
47    }
48
49    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
50        if data.len() == 1 && data[0] == 0xfe && info.address == 0x64 {
51            if let Err(e) = self
52                .reset_evt_wrtube
53                .send::<VmEventType>(&VmEventType::Reset)
54            {
55                error!("failed to trigger i8042 reset event: {}", e);
56            }
57        }
58    }
59}
60
61impl Suspendable for I8042Device {
62    fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
63        AnySnapshot::to_any(())
64    }
65
66    fn restore(&mut self, _data: AnySnapshot) -> anyhow::Result<()> {
67        Ok(())
68    }
69
70    fn sleep(&mut self) -> anyhow::Result<()> {
71        Ok(())
72    }
73
74    fn wake(&mut self) -> anyhow::Result<()> {
75        Ok(())
76    }
77}