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