use crate::drivers::platform::pic; use crate::io::{disable_interrupts, enable_interrupts, inb}; const DATA_PORT: u16 = 0x60; const STATUS_PORT: u16 = 0x64; const OUTPUT_FULL: u8 = 1 << 0; const BUFFER_SIZE: usize = 256; static mut KEYBOARD: Ps2Keyboard = Ps2Keyboard::new(); pub struct Ps2Keyboard { buffer: [u8; BUFFER_SIZE], read_index: usize, write_index: usize, shift: bool, extended: bool, } impl Ps2Keyboard { const fn new() -> Self { Self { buffer: [0; BUFFER_SIZE], read_index: 0, write_index: 0, shift: false, extended: false, } } fn push(&mut self, byte: u8) { let next = (self.write_index + 1) % BUFFER_SIZE; if next != self.read_index { self.buffer[self.write_index] = byte; self.write_index = next; } } fn pop(&mut self) -> Option { if self.read_index == self.write_index { return None; } let byte = self.buffer[self.read_index]; self.read_index = (self.read_index + 1) % BUFFER_SIZE; Some(byte) } fn handle_scancode(&mut self, scancode: u8) { if scancode == 0xe0 { self.extended = true; return; } if self.extended { self.extended = false; if scancode & 0x80 != 0 { return; } match scancode { 0x48 => self.push_escape_sequence(b"\x1b[A"), 0x50 => self.push_escape_sequence(b"\x1b[B"), 0x4b => self.push_escape_sequence(b"\x1b[D"), 0x4d => self.push_escape_sequence(b"\x1b[C"), 0x47 => self.push_escape_sequence(b"\x1b[H"), 0x4f => self.push_escape_sequence(b"\x1b[F"), 0x53 => self.push_escape_sequence(b"\x1b[3~"), _ => {} } return; } let released = scancode & 0x80 != 0; let code = scancode & 0x7f; match code { 0x2a | 0x36 => { self.shift = !released; return; } _ if released => return, _ => {} } if let Some(ascii) = scancode_set1_to_ascii(code, self.shift) { self.push(ascii); } } fn push_escape_sequence(&mut self, bytes: &[u8]) { for byte in bytes { self.push(*byte); } } } pub unsafe fn init() { unsafe { drain_output_buffer(); pic::unmask_irq(pic::KEYBOARD_IRQ); } } #[unsafe(no_mangle)] pub extern "C" fn zeroos_ps2_keyboard_interrupt() { unsafe { if inb(STATUS_PORT) & OUTPUT_FULL != 0 { let scancode = inb(DATA_PORT); (*(&raw mut KEYBOARD)).handle_scancode(scancode); } pic::end_of_interrupt(pic::KEYBOARD_IRQ); } } pub fn read_char() -> Option { disable_interrupts(); let ch = unsafe { (*(&raw mut KEYBOARD)).pop() }; enable_interrupts(); ch } pub fn has_char() -> bool { disable_interrupts(); let ready = unsafe { let keyboard = &*(&raw const KEYBOARD); keyboard.read_index != keyboard.write_index }; enable_interrupts(); ready } unsafe fn drain_output_buffer() { unsafe { while inb(STATUS_PORT) & OUTPUT_FULL != 0 { let _ = inb(DATA_PORT); } } } fn scancode_set1_to_ascii(code: u8, shift: bool) -> Option { let byte = match code { 0x01 => 0x1b, 0x02 => { if shift { b'!' } else { b'1' } } 0x03 => { if shift { b'@' } else { b'2' } } 0x04 => { if shift { b'#' } else { b'3' } } 0x05 => { if shift { b'$' } else { b'4' } } 0x06 => { if shift { b'%' } else { b'5' } } 0x07 => { if shift { b'^' } else { b'6' } } 0x08 => { if shift { b'&' } else { b'7' } } 0x09 => { if shift { b'*' } else { b'8' } } 0x0a => { if shift { b'(' } else { b'9' } } 0x0b => { if shift { b')' } else { b'0' } } 0x0c => { if shift { b'_' } else { b'-' } } 0x0d => { if shift { b'+' } else { b'=' } } 0x0e => 0x08, 0x0f => b'\t', 0x10 => letter(b'q', shift), 0x11 => letter(b'w', shift), 0x12 => letter(b'e', shift), 0x13 => letter(b'r', shift), 0x14 => letter(b't', shift), 0x15 => letter(b'y', shift), 0x16 => letter(b'u', shift), 0x17 => letter(b'i', shift), 0x18 => letter(b'o', shift), 0x19 => letter(b'p', shift), 0x1a => { if shift { b'{' } else { b'[' } } 0x1b => { if shift { b'}' } else { b']' } } 0x1c => b'\r', 0x1e => letter(b'a', shift), 0x1f => letter(b's', shift), 0x20 => letter(b'd', shift), 0x21 => letter(b'f', shift), 0x22 => letter(b'g', shift), 0x23 => letter(b'h', shift), 0x24 => letter(b'j', shift), 0x25 => letter(b'k', shift), 0x26 => letter(b'l', shift), 0x27 => { if shift { b':' } else { b';' } } 0x28 => { if shift { b'"' } else { b'\'' } } 0x29 => { if shift { b'~' } else { b'`' } } 0x2b => { if shift { b'|' } else { b'\\' } } 0x2c => letter(b'z', shift), 0x2d => letter(b'x', shift), 0x2e => letter(b'c', shift), 0x2f => letter(b'v', shift), 0x30 => letter(b'b', shift), 0x31 => letter(b'n', shift), 0x32 => letter(b'm', shift), 0x33 => { if shift { b'<' } else { b',' } } 0x34 => { if shift { b'>' } else { b'.' } } 0x35 => { if shift { b'?' } else { b'/' } } 0x39 => b' ', _ => return None, }; Some(byte) } const fn letter(lower: u8, shift: bool) -> u8 { if shift { lower - 32 } else { lower } }