xref: /cloud-hypervisor/devices/src/legacy/i8042.rs (revision f67b3f79ea19c9a66e04074cbbf5d292f6529e43)
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE-BSD-3-Clause file.
4 
5 use std::sync::{Arc, Barrier};
6 use vm_device::BusDevice;
7 use vmm_sys_util::eventfd::EventFd;
8 
9 /// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
10 pub struct I8042Device {
11     reset_evt: EventFd,
12 }
13 
14 impl I8042Device {
15     /// Constructs a i8042 device that will signal the given event when the guest requests it.
16     pub fn new(reset_evt: EventFd) -> I8042Device {
17         I8042Device { reset_evt }
18     }
19 }
20 
21 // i8042 device is located at I/O port 0x61. We partially implement two 8-bit
22 // registers: port 0x61 (I8042_PORT_B_REG, offset 0 from base of 0x61), and
23 // port 0x64 (I8042_COMMAND_REG, offset 3 from base of 0x61).
24 impl BusDevice for I8042Device {
25     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
26         if data.len() == 1 && offset == 3 {
27             data[0] = 0x0;
28         } else if data.len() == 1 && offset == 0 {
29             // Like kvmtool, we return bit 5 set in I8042_PORT_B_REG to
30             // avoid hang in pit_calibrate_tsc() in Linux kernel.
31             data[0] = 0x20;
32         }
33     }
34 
35     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
36         if data.len() == 1 && data[0] == 0xfe && offset == 3 {
37             info!("i8042 reset signalled");
38             if let Err(e) = self.reset_evt.write(1) {
39                 error!("Error triggering i8042 reset event: {}", e);
40             }
41         }
42 
43         None
44     }
45 }
46