strat9_kernel/arch/x86_64/
keyboard.rs1use super::io::{inb, outb};
10use core::sync::atomic::{AtomicUsize, Ordering};
11use spin::Mutex;
12
13const KEYBOARD_BUFFER_SIZE: usize = 256;
15
16struct KeyboardBufferInner {
23 buf: [u8; KEYBOARD_BUFFER_SIZE],
24 head: usize,
25 tail: usize,
26}
27
28struct KeyboardBuffer {
29 inner: Mutex<KeyboardBufferInner>,
30}
31
32static KEYBOARD_BUFFER: KeyboardBuffer = KeyboardBuffer::new();
33
34static LOST_KEY_COUNT: AtomicUsize = AtomicUsize::new(0);
37
38impl KeyboardBuffer {
39 const fn new() -> Self {
40 Self {
41 inner: Mutex::new(KeyboardBufferInner {
42 buf: [0u8; KEYBOARD_BUFFER_SIZE],
43 head: 0,
44 tail: 0,
45 }),
46 }
47 }
48
49 pub fn push(&self, ch: u8) {
51 let mut g = self.inner.lock();
52 let tail = g.tail;
53 g.buf[tail] = ch;
54 g.tail = (tail + 1) % KEYBOARD_BUFFER_SIZE;
55 if g.head == g.tail {
57 g.head = (g.head + 1) % KEYBOARD_BUFFER_SIZE;
58 LOST_KEY_COUNT.fetch_add(1, Ordering::Relaxed);
59 }
60 }
61
62 pub fn pop(&self) -> Option<u8> {
64 let saved = super::save_flags_and_cli();
65 let result = {
66 let mut g = self.inner.lock();
67 if g.head == g.tail {
68 None
69 } else {
70 let ch = g.buf[g.head];
71 g.head = (g.head + 1) % KEYBOARD_BUFFER_SIZE;
72 Some(ch)
73 }
74 };
75 super::restore_flags(saved);
76 result
77 }
78
79 pub fn has_data(&self) -> bool {
81 let saved = super::save_flags_and_cli();
82 let result = {
83 let g = self.inner.lock();
84 g.head != g.tail
85 };
86 super::restore_flags(saved);
87 result
88 }
89}
90
91pub fn add_to_buffer(ch: u8) {
95 if ch == 0x03 {
96 crate::shell::SHELL_INTERRUPTED.store(true, Ordering::Relaxed);
97 }
98 KEYBOARD_BUFFER.push(ch);
99}
100
101pub fn read_char() -> Option<u8> {
103 KEYBOARD_BUFFER.pop()
104}
105
106pub fn has_input() -> bool {
108 KEYBOARD_BUFFER.has_data()
109}
110
111pub fn lost_key_count() -> usize {
113 LOST_KEY_COUNT.load(Ordering::Relaxed)
114}
115
116pub fn reset_lost_key_count() {
118 LOST_KEY_COUNT.store(0, Ordering::Relaxed);
119}
120
121pub fn inject_hid_scancode(scancode: u8, pressed: bool) {
126 let raw = if pressed { scancode } else { scancode | 0x80 };
127 if let Some(ch) = super::keyboard_layout::handle_scancode_raw(raw) {
128 let saved = super::save_flags_and_cli();
129 KEYBOARD_BUFFER.push(ch);
130 super::restore_flags(saved);
131 }
132}
133
134pub use super::keyboard_layout::{KEY_DOWN, KEY_END, KEY_HOME, KEY_LEFT, KEY_RIGHT, KEY_UP};
136
137pub(crate) const KEYBOARD_DATA_PORT: u16 = 0x60;
139const PS2_CMD_PORT: u16 = 0x64;
140
141const CMD_READ_CFG: u8 = 0x20;
142const CMD_WRITE_CFG: u8 = 0x60;
143const CMD_ENABLE_KBD: u8 = 0xAE;
144
145const STATUS_OUTPUT_FULL: u8 = 0x01;
146const STATUS_INPUT_FULL: u8 = 0x02;
147
148#[inline]
149fn wait_write() {
150 for _ in 0..100_000u32 {
151 if unsafe { inb(PS2_CMD_PORT) } & STATUS_INPUT_FULL == 0 {
152 return;
153 }
154 core::hint::spin_loop();
155 }
156}
157
158#[inline]
159fn wait_read() {
160 for _ in 0..100_000u32 {
161 if unsafe { inb(PS2_CMD_PORT) } & STATUS_OUTPUT_FULL != 0 {
162 return;
163 }
164 core::hint::spin_loop();
165 }
166}
167
168fn ps2_read() -> u8 {
169 wait_read();
170 unsafe { inb(KEYBOARD_DATA_PORT) }
171}
172
173fn ps2_write_cmd(cmd: u8) {
174 wait_write();
175 unsafe { outb(PS2_CMD_PORT, cmd) };
176}
177
178fn ps2_write_data(data: u8) {
179 wait_write();
180 unsafe { outb(KEYBOARD_DATA_PORT, data) };
181}
182
183fn flush_output() {
184 for _ in 0..16 {
185 if unsafe { inb(PS2_CMD_PORT) } & STATUS_OUTPUT_FULL == 0 {
186 break;
187 }
188 unsafe { inb(KEYBOARD_DATA_PORT) };
189 }
190}
191
192pub fn init() {
197 flush_output();
198
199 ps2_write_cmd(CMD_ENABLE_KBD);
200
201 ps2_write_cmd(CMD_READ_CFG);
202 let mut cfg = ps2_read();
203 cfg |= 0x01;
204 cfg &= !0x10;
205 ps2_write_cmd(CMD_WRITE_CFG);
206 ps2_write_data(cfg);
207
208 flush_output();
209}