kernel/devices/keyboard_mouse/
ps2.rs1use crate::cpu;
2
3const PS2_STATUS_PORT: u16 = 0x64;
4const PS2_DATA_PORT: u16 = 0x60;
5
6#[allow(dead_code)]
7pub mod status {
8 pub const DATA_READY: u8 = 1 << 0;
9 pub const INPUT_BUFFER_FULL: u8 = 1 << 1;
10 pub const SYSTEM_FLAG: u8 = 1 << 2;
11 pub const COMMAND_DATA: u8 = 1 << 3;
12 pub const KEYBOARD_LOCKED: u8 = 1 << 4;
13 pub const KEYBOARD_TIMEOUT_MOUSE_DATA: u8 = 1 << 5;
14 pub const RECEIVE_TIMEOUT: u8 = 1 << 6;
15 pub const PARITY_ERROR: u8 = 1 << 7;
16}
17
18#[derive(Debug, Clone, Copy)]
19pub struct Ps2;
20
21impl Ps2 {
22 pub fn read_data(&self) -> u8 {
23 unsafe { cpu::io_in(PS2_DATA_PORT) }
24 }
25
26 fn wait_for_ack(&self) -> (bool, bool) {
28 let mut timeout = 1000;
29 while timeout > 0 {
30 if self.read_status() & status::DATA_READY != 0 {
31 let data = self.read_data();
32 match data {
33 0xFA => return (true, false),
34 0xFE => return (false, true),
35 _ => {}
36 }
37 panic!("unexpected data from mouse: {:#X}, waiting for ack", data)
38 }
39 timeout -= 1;
40 }
41 (false, false)
42 }
43
44 pub fn read_status(&self) -> u8 {
45 unsafe { cpu::io_in(PS2_STATUS_PORT) }
46 }
47
48 pub fn has_data(&self) -> bool {
49 self.read_status() & status::DATA_READY != 0
50 }
51
52 pub fn write_prefix(&self, prefix: u8) {
53 self.wait_for_command_clear();
54 unsafe { cpu::io_out(PS2_STATUS_PORT, prefix) }
55 }
56
57 fn write_data(&self, data: u8) {
58 unsafe { cpu::io_out(PS2_DATA_PORT, data) }
59 }
60
61 pub fn wait_read_data(&self) -> u8 {
62 loop {
63 if self.read_status() & status::DATA_READY != 0 {
64 return self.read_data();
65 }
66 }
67 }
68
69 pub fn wait_read_data_slice(&self, data: &mut [u8]) {
70 for byte in data.iter_mut() {
71 *byte = self.wait_read_data();
72 }
73 }
74
75 #[must_use]
76 pub fn write_command_data(&self, data: u8) -> Option<()> {
77 let mut attempts = 3;
78 loop {
79 self.wait_for_command_clear();
80 self.write_data(data);
81 let (ack, resend) = self.wait_for_ack();
82
83 if resend {
84 attempts -= 1;
85 if attempts == 0 {
86 return None;
87 }
88 continue;
89 }
90
91 if ack {
92 return Some(());
93 }
94 }
95 }
96
97 pub fn wait_for_command_clear(&self) {
98 while self.read_status() & status::DATA_READY != 0 {
99 self.read_data();
101 }
102 while self.read_status() & status::INPUT_BUFFER_FULL != 0 {
103 core::hint::spin_loop();
105 }
106 }
107
108 pub fn reset_system(&self) -> ! {
109 self.write_prefix(0xFE);
110 loop {
111 unsafe { cpu::halt() };
112 }
113 }
114}