strat9_kernel/arch/x86_64/
keyboard.rs1use super::io::{inb, outb};
7use spin::Mutex;
8
9const KEYBOARD_BUFFER_SIZE: usize = 256;
11
12struct KeyboardBufferInner {
30 buf: [u8; KEYBOARD_BUFFER_SIZE],
31 head: usize,
32 tail: usize,
33}
34
35struct KeyboardBuffer {
36 inner: Mutex<KeyboardBufferInner>,
37}
38
39static KEYBOARD_BUFFER: KeyboardBuffer = KeyboardBuffer::new();
40
41impl KeyboardBuffer {
42 const fn new() -> Self {
44 Self {
45 inner: Mutex::new(KeyboardBufferInner {
46 buf: [0u8; KEYBOARD_BUFFER_SIZE],
47 head: 0,
48 tail: 0,
49 }),
50 }
51 }
52
53 pub fn push(&self, ch: u8) {
56 let mut g = self.inner.lock();
57 let tail = g.tail;
58 g.buf[tail] = ch;
59 g.tail = (tail + 1) % KEYBOARD_BUFFER_SIZE;
60 if g.head == g.tail {
62 g.head = (g.head + 1) % KEYBOARD_BUFFER_SIZE;
63 }
64 }
65
66 pub fn pop(&self) -> Option<u8> {
69 let saved = super::save_flags_and_cli();
70 let result = {
71 let mut g = self.inner.lock();
72 if g.head == g.tail {
73 None
74 } else {
75 let ch = g.buf[g.head];
76 g.head = (g.head + 1) % KEYBOARD_BUFFER_SIZE;
77 Some(ch)
78 }
79 };
80 super::restore_flags(saved);
81 result
82 }
83
84 pub fn has_data(&self) -> bool {
86 let saved = super::save_flags_and_cli();
87 let result = {
88 let g = self.inner.lock();
89 g.head != g.tail
90 };
91 super::restore_flags(saved);
92 result
93 }
94}
95
96pub fn add_to_buffer(ch: u8) {
107 if ch == 0x03 {
108 crate::shell::SHELL_INTERRUPTED.store(true, core::sync::atomic::Ordering::Relaxed);
109 }
110 KEYBOARD_BUFFER.push(ch);
111}
112
113pub fn read_char() -> Option<u8> {
115 KEYBOARD_BUFFER.pop()
116}
117
118pub fn has_input() -> bool {
120 KEYBOARD_BUFFER.has_data()
121}
122
123pub fn inject_hid_scancode(scancode: u8, pressed: bool) {
132 let raw = if pressed { scancode } else { scancode | 0x80 };
133 if let Some(ch) = super::keyboard_layout::handle_scancode_raw(raw) {
134 let saved = super::save_flags_and_cli();
135 KEYBOARD_BUFFER.push(ch);
136 super::restore_flags(saved);
137 }
138}
139
140const KEYBOARD_DATA_PORT: u16 = 0x60;
142const PS2_CMD_PORT: u16 = 0x64;
143
144const CMD_READ_CFG: u8 = 0x20;
145const CMD_WRITE_CFG: u8 = 0x60;
146const CMD_ENABLE_KBD: u8 = 0xAE;
147
148const STATUS_OUTPUT_FULL: u8 = 0x01;
149const STATUS_INPUT_FULL: u8 = 0x02;
150
151#[inline]
152fn wait_write() {
153 for _ in 0..100_000u32 {
154 if unsafe { inb(PS2_CMD_PORT) } & STATUS_INPUT_FULL == 0 {
155 return;
156 }
157 core::hint::spin_loop();
158 }
159}
160
161#[inline]
162fn wait_read() {
163 for _ in 0..100_000u32 {
164 if unsafe { inb(PS2_CMD_PORT) } & STATUS_OUTPUT_FULL != 0 {
165 return;
166 }
167 core::hint::spin_loop();
168 }
169}
170
171fn ps2_read() -> u8 {
172 wait_read();
173 unsafe { inb(KEYBOARD_DATA_PORT) }
174}
175
176fn ps2_write_cmd(cmd: u8) {
177 wait_write();
178 unsafe { outb(PS2_CMD_PORT, cmd) };
179}
180
181fn ps2_write_data(data: u8) {
182 wait_write();
183 unsafe { outb(KEYBOARD_DATA_PORT, data) };
184}
185
186fn flush_output() {
187 for _ in 0..16 {
188 if unsafe { inb(PS2_CMD_PORT) } & STATUS_OUTPUT_FULL == 0 {
189 break;
190 }
191 unsafe { inb(KEYBOARD_DATA_PORT) };
192 }
193}
194
195pub fn init() {
201 flush_output();
202
203 ps2_write_cmd(CMD_ENABLE_KBD);
204
205 ps2_write_cmd(CMD_READ_CFG);
206 let mut cfg = ps2_read();
207 cfg |= 0x01;
208 cfg &= !0x10;
209 ps2_write_cmd(CMD_WRITE_CFG);
210 ps2_write_data(cfg);
211
212 flush_output();
213}
214
215pub struct KeyboardState {
217 pub left_shift: bool,
219 pub right_shift: bool,
221 pub caps_lock: bool,
223 pub ctrl: bool,
225 pub alt: bool,
227}
228
229impl KeyboardState {
230 pub const fn new() -> Self {
232 Self {
233 left_shift: false,
234 right_shift: false,
235 caps_lock: false,
236 ctrl: false,
237 alt: false,
238 }
239 }
240
241 pub fn shift_active(&self) -> bool {
243 self.left_shift || self.right_shift
244 }
245}
246
247pub static KEYBOARD: Mutex<KeyboardState> = Mutex::new(KeyboardState::new());
249
250static SCANCODE_TO_ASCII: [u8; 128] = {
252 let mut table = [0u8; 128];
253 table[0x01] = 0x1B; table[0x02] = b'&'; table[0x03] = b'e'; table[0x04] = b'"'; table[0x05] = b'\''; table[0x06] = b'('; table[0x07] = b'-'; table[0x08] = b'e'; table[0x09] = b'_'; table[0x0A] = b'c'; table[0x0B] = b'a'; table[0x0C] = b')'; table[0x0D] = b'='; table[0x0E] = 0x08; table[0x0F] = b'\t';
270 table[0x10] = b'a'; table[0x11] = b'z'; table[0x12] = b'e'; table[0x13] = b'r'; table[0x14] = b't'; table[0x15] = b'y'; table[0x16] = b'u'; table[0x17] = b'i'; table[0x18] = b'o'; table[0x19] = b'p'; table[0x1A] = b'^'; table[0x1B] = b'$'; table[0x1C] = b'\n'; table[0x1E] = b'q'; table[0x1F] = b's'; table[0x20] = b'd'; table[0x21] = b'f'; table[0x22] = b'g'; table[0x23] = b'h'; table[0x24] = b'j'; table[0x25] = b'k'; table[0x26] = b'l'; table[0x27] = b'm'; table[0x28] = b'u'; table[0x29] = b'*'; table[0x2A] = 0x00; table[0x2B] = b'<'; table[0x2C] = b'w'; table[0x2D] = b'x'; table[0x2E] = b'c'; table[0x2F] = b'v'; table[0x30] = b'b'; table[0x31] = b'n'; table[0x32] = b','; table[0x33] = b';'; table[0x34] = b'.'; table[0x35] = b'/'; table[0x39] = b' ';
311 table
312};
313
314static SCANCODE_TO_ASCII_SHIFT: [u8; 128] = {
316 let mut table = [0u8; 128];
317 table[0x01] = 0x1B; table[0x02] = b'1'; table[0x03] = b'2'; table[0x04] = b'3'; table[0x05] = b'4'; table[0x06] = b'5'; table[0x07] = b'6'; table[0x08] = b'7'; table[0x09] = b'8'; table[0x0A] = b'9'; table[0x0B] = b'0'; table[0x0C] = b')'; table[0x0D] = b'+'; table[0x0E] = 0x08; table[0x0F] = b'\t'; table[0x10] = b'A'; table[0x11] = b'Z'; table[0x12] = b'E'; table[0x13] = b'R'; table[0x14] = b'T'; table[0x15] = b'Y'; table[0x16] = b'U'; table[0x17] = b'I'; table[0x18] = b'O'; table[0x19] = b'P'; table[0x1A] = b'^'; table[0x1B] = b'*'; table[0x1C] = b'\n'; table[0x1E] = b'Q'; table[0x1F] = b'S'; table[0x20] = b'D'; table[0x21] = b'F'; table[0x22] = b'G'; table[0x23] = b'H'; table[0x24] = b'J'; table[0x25] = b'K'; table[0x26] = b'L'; table[0x27] = b'M'; table[0x28] = b'%'; table[0x29] = b'm'; table[0x2B] = b'>'; table[0x2C] = b'W'; table[0x2D] = b'X'; table[0x2E] = b'C'; table[0x2F] = b'V'; table[0x30] = b'B'; table[0x31] = b'N'; table[0x32] = b'?'; table[0x33] = b'.'; table[0x34] = b','; table[0x35] = b'/'; table[0x39] = b' '; table
370};
371
372pub const KEY_UP: u8 = 0x80;
374pub const KEY_DOWN: u8 = 0x81;
375pub const KEY_LEFT: u8 = 0x82;
376pub const KEY_RIGHT: u8 = 0x83;
377pub const KEY_HOME: u8 = 0x84;
378pub const KEY_END: u8 = 0x85;
379
380pub fn handle_scancode() -> Option<u8> {
385 let scancode = unsafe { inb(KEYBOARD_DATA_PORT) };
386 handle_scancode_raw(scancode)
387}
388
389pub fn handle_scancode_raw(scancode: u8) -> Option<u8> {
391 let mut kbd = KEYBOARD.lock();
392
393 if scancode & 0x80 != 0 {
395 let released = scancode & 0x7F;
396 match released {
397 0x2A => kbd.left_shift = false,
398 0x36 => kbd.right_shift = false,
399 0x1D => kbd.ctrl = false,
400 0x38 => kbd.alt = false,
401 _ => {}
402 }
403 return None;
404 }
405
406 match scancode {
408 0x2A => {
409 kbd.left_shift = true;
410 return None;
411 }
412 0x36 => {
413 kbd.right_shift = true;
414 return None;
415 }
416 0x1D => {
417 kbd.ctrl = true;
418 return None;
419 }
420 0x38 => {
421 kbd.alt = true;
422 return None;
423 }
424 0x3A => {
425 kbd.caps_lock = !kbd.caps_lock;
426 return None;
427 }
428 0x48 => return Some(KEY_UP),
430 0x50 => return Some(KEY_DOWN),
431 0x4B => return Some(KEY_LEFT),
432 0x4D => return Some(KEY_RIGHT),
433 0x47 => return Some(KEY_HOME),
434 0x4F => return Some(KEY_END),
435 _ => {}
436 }
437
438 if scancode < 128 {
440 let shift = kbd.shift_active();
441 let ch = if shift {
442 SCANCODE_TO_ASCII_SHIFT[scancode as usize]
443 } else {
444 SCANCODE_TO_ASCII[scancode as usize]
445 };
446
447 if kbd.caps_lock && ch.is_ascii_alphabetic() {
449 let ch = if shift {
450 ch.to_ascii_lowercase()
451 } else {
452 ch.to_ascii_uppercase()
453 };
454 if ch != 0 {
455 return Some(ch);
456 }
457 }
458
459 if ch != 0 {
460 return Some(ch);
461 }
462 }
463
464 None
465}