// --------------------------------------------------------------------------- // Shared USB HID helpers: boot-keyboard report decoding into scancode-set-1 // bytes, plus the FIFO the drivers hand to the PS/2 decoder. // // Every HID keyboard (UHCI, EHCI, xHCI) feeds the same `ps2::feed_scancode` // state machine, so a USB keyboard behaves exactly like the PS/2 one. The // per-report diff state lives in `Keyboard` (one instance per device); the // byte FIFO is shared because the consumer is a single scancode stream. // --------------------------------------------------------------------------- use core::sync::atomic::Ordering; /// HID usage -> scancode set 1 (make code). High byte 0xE0 = E0-prefixed. /// 0 = unmapped. Table covers the common keyboard usages (0x04..0x63). static HID_TO_SCAN: [u16; 0x64] = { let mut t = [0u16; 0x64]; let mut i = 0; while i < 0x64 { t[i] = 0; i += 1; } // Letters a-z t[0x04] = 0x1E; t[0x05] = 0x30; t[0x06] = 0x2E; t[0x07] = 0x20; t[0x08] = 0x12; t[0x09] = 0x21; t[0x0A] = 0x22; t[0x0B] = 0x23; t[0x0C] = 0x17; t[0x0D] = 0x24; t[0x0E] = 0x25; t[0x0F] = 0x26; t[0x10] = 0x32; t[0x11] = 0x31; t[0x12] = 0x18; t[0x13] = 0x19; t[0x14] = 0x10; t[0x15] = 0x13; t[0x16] = 0x1F; t[0x17] = 0x14; t[0x18] = 0x16; t[0x19] = 0x2F; t[0x1A] = 0x11; t[0x1B] = 0x2D; t[0x1C] = 0x15; t[0x1D] = 0x2C; // Digits + punctuation t[0x1E] = 0x02; t[0x1F] = 0x03; t[0x20] = 0x04; t[0x21] = 0x05; t[0x22] = 0x06; t[0x23] = 0x07; t[0x24] = 0x08; t[0x25] = 0x09; t[0x26] = 0x0A; t[0x27] = 0x0B; t[0x28] = 0x1C; // Enter t[0x29] = 0x01; // Esc t[0x2A] = 0x0E; // Backspace t[0x2B] = 0x0F; // Tab t[0x2C] = 0x39; // Space t[0x2D] = 0x0C; // - t[0x2E] = 0x0D; // = t[0x2F] = 0x1A; // [ t[0x30] = 0x1B; // ] t[0x31] = 0x2B; // backslash t[0x33] = 0x27; // ; t[0x34] = 0x28; // ' t[0x35] = 0x29; // ` t[0x36] = 0x33; // , t[0x37] = 0x34; // . t[0x38] = 0x35; // / t[0x39] = 0x3A; // CapsLock // F-keys t[0x3A] = 0x3B; // F1 t[0x3B] = 0x3C; t[0x3C] = 0x3D; t[0x3D] = 0x3E; t[0x3E] = 0x3F; t[0x3F] = 0x40; t[0x40] = 0x41; t[0x41] = 0x42; t[0x42] = 0x43; t[0x43] = 0x44; // F10 t[0x44] = 0xE057; // F11 t[0x45] = 0xE058; // F12 // Nav cluster t[0x49] = 0xE052; // Insert t[0x4A] = 0xE047; // Home t[0x4B] = 0xE049; // PageUp t[0x4C] = 0xE053; // Delete t[0x4D] = 0xE04F; // End t[0x4E] = 0xE051; // PageDown t[0x4F] = 0xE04D; // Right t[0x50] = 0xE04B; // Left t[0x51] = 0xE050; // Down t[0x52] = 0xE048; // Up // Keypad t[0x53] = 0x45; // NumLock t[0x54] = 0xE035; // / t[0x55] = 0x37; // * t[0x56] = 0x4A; // - t[0x57] = 0x4E; // + t[0x58] = 0xE01C; // Enter t[0x59] = 0x4F; // 1 t[0x5A] = 0x50; // 2 t[0x5B] = 0x51; // 3 t[0x5C] = 0x4B; // 4 t[0x5D] = 0x4C; // 5 t[0x5E] = 0x4D; // 6 t[0x5F] = 0x47; // 7 t[0x60] = 0x48; // 8 t[0x61] = 0x49; // 9 t[0x62] = 0x52; // 0 t[0x63] = 0x53; // . t }; /// Modifier bit -> scancode (set 1, high byte 0xE0 = E0-prefixed). static MOD_TO_SCAN: [u16; 8] = [ 0x1D, // 0 LCtrl 0x2A, // 1 LShift 0x38, // 2 LAlt 0xE05B, // 3 LGui 0xE01D, // 4 RCtrl 0x36, // 5 RShift 0xE038, // 6 RAlt 0xE05C, // 7 RGui ]; // ---- scancode FIFO (shared: one PS/2 decoder consumer) ---- const Q_SIZE: usize = 128; static mut Q: [u8; Q_SIZE] = [0; Q_SIZE]; static Q_HEAD: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); static Q_LEN: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); /// Queue one scancode-set-1 byte (drops when the FIFO is full). pub fn push_byte(b: u8) { unsafe { let h = Q_HEAD.load(Ordering::Relaxed) as usize; let l = Q_LEN.load(Ordering::Relaxed) as usize; if l >= Q_SIZE { return; } Q[(h + l) % Q_SIZE] = b; Q_LEN.store((l + 1) as u32, Ordering::Relaxed); } } /// Pop one queued scancode byte (callers feed it to `ps2::feed_scancode`). pub fn pop_byte() -> Option { unsafe { let l = Q_LEN.load(Ordering::Relaxed) as usize; if l == 0 { return None; } let h = Q_HEAD.load(Ordering::Relaxed) as usize; let b = Q[h]; Q_HEAD.store(((h + 1) % Q_SIZE) as u32, Ordering::Relaxed); Q_LEN.store((l - 1) as u32, Ordering::Relaxed); Some(b) } } /// Push the make (press) or break (release) scancode sequence for a /// scancode-map entry (0 = unmapped, 0x00XX = plain, 0xE0XX = E0-prefixed). pub fn push_scancode(scan: u16, press: bool) { if scan == 0 { return; } if scan & 0xFF00 == 0xE000 { push_byte(0xE0); let code = (scan & 0xFF) as u8; push_byte(if press { code } else { code | 0x80 }); } else { let code = scan as u8; push_byte(if press { code } else { code | 0x80 }); } } /// Per-device boot-keyboard report differ. Boot protocol reports are /// 8 bytes: modifiers, reserved, 6 usage codes. pub struct Keyboard { prev: [u8; 8], } impl Keyboard { pub const fn new() -> Self { Self { prev: [0; 8] } } /// Diff `report` against the previous one and queue make/break bytes. pub fn diff(&mut self, report: &[u8]) { let mut rep = [0u8; 8]; for (i, b) in rep.iter_mut().enumerate() { *b = report.get(i).copied().unwrap_or(0); } let new_mods = rep[0]; let old_mods = self.prev[0]; for bit in 0..8 { let new_set = new_mods & (1 << bit) != 0; let old_set = old_mods & (1 << bit) != 0; if new_set != old_set { push_scancode(MOD_TO_SCAN[bit], new_set); } } let new_keys = &rep[2..8]; let old_keys = &self.prev[2..8]; // Releases first (old keys not in the new set). for &k in old_keys { if k == 0 || new_keys.contains(&k) { continue; } if (k as usize) < HID_TO_SCAN.len() { push_scancode(HID_TO_SCAN[k as usize], false); } } // Then presses (new keys not in the old set). for &k in new_keys { if k == 0 || old_keys.contains(&k) { continue; } if (k as usize) < HID_TO_SCAN.len() { push_scancode(HID_TO_SCAN[k as usize], true); } } self.prev = rep; } }