diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-01 16:05:09 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-01 16:05:09 +0100 |
| commit | 561354b69c5ae5e73b036b382988fda02bc9fb01 (patch) | |
| tree | e030b0c493637502f24e0f6e60ae2ca4418e0c03 | |
| parent | scripts: rebuild the dev loop around build.sh/run.sh (diff) | |
| download | rs-dos-561354b69c5ae5e73b036b382988fda02bc9fb01.tar.gz rs-dos-561354b69c5ae5e73b036b382988fda02bc9fb01.zip | |
usb: re-enable EHCI, share HID keyboard decoding, fix boot protocol
- ehci: DEBUG_MATRIX was left true in be868a4, so every boot replaced
enumeration with the one-shot diagnostic transfer matrix and returned
false -- the EHCI driver never brought a device up. Default it off;
flip it back on only when bisecting a controller fault.
- new rsnix/src/hid.rs: boot-keyboard HID usage -> scancode-set-1
tables, the shared scancode FIFO, and a per-device report differ.
UHCI now uses it instead of its own copy, so EHCI/xHCI keyboards can
feed the same PS/2 decoder (`ps2::feed_scancode`).
- uhci: SET_PROTOCOL now asks for the boot protocol (wValue 0) instead
of report protocol (wValue 1). In report protocol the report layout
is device-defined, but every driver parses boot reports.
| -rw-r--r-- | rsnix/src/ehci.rs | 7 | ||||
| -rw-r--r-- | rsnix/src/hid.rs | 232 | ||||
| -rw-r--r-- | rsnix/src/lib.rs | 1 | ||||
| -rw-r--r-- | rsnix/src/uhci.rs | 228 |
4 files changed, 253 insertions, 215 deletions
diff --git a/rsnix/src/ehci.rs b/rsnix/src/ehci.rs index 6209155..8baa0ad 100644 --- a/rsnix/src/ehci.rs +++ b/rsnix/src/ehci.rs | |||
| @@ -89,7 +89,12 @@ static QR_SHOWN: AtomicBool = AtomicBool::new(false); | |||
| 89 | // DEBUG: run the one-boot transfer variant matrix (real-hardware bisection | 89 | // DEBUG: run the one-boot transfer variant matrix (real-hardware bisection |
| 90 | // of the EHCI System Error trigger). MATRIX_DONE gates it to one pass; | 90 | // of the EHCI System Error trigger). MATRIX_DONE gates it to one pass; |
| 91 | // XFER_TWEAK flips construction variables inside ctl_xfer. | 91 | // XFER_TWEAK flips construction variables inside ctl_xfer. |
| 92 | static DEBUG_MATRIX: bool = true; | 92 | // |
| 93 | // OFF in normal builds: with it on, `enumerate()` is replaced by the | ||
| 94 | // diagnostic matrix and returns false, i.e. the EHCI driver never brings a | ||
| 95 | // device up. Flip to true only when bisecting a hardware fault, and expect | ||
| 96 | // no USB input in that build. | ||
| 97 | static DEBUG_MATRIX: bool = false; | ||
| 93 | static MATRIX_DONE: AtomicBool = AtomicBool::new(false); | 98 | static MATRIX_DONE: AtomicBool = AtomicBool::new(false); |
| 94 | static XFER_TWEAK: AtomicU32 = AtomicU32::new(0); | 99 | static XFER_TWEAK: AtomicU32 = AtomicU32::new(0); |
| 95 | // Low-region (<1 MB) control QH for the matrix's low-region variant. | 100 | // Low-region (<1 MB) control QH for the matrix's low-region variant. |
diff --git a/rsnix/src/hid.rs b/rsnix/src/hid.rs new file mode 100644 index 0000000..42c7602 --- /dev/null +++ b/rsnix/src/hid.rs | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | // --------------------------------------------------------------------------- | ||
| 2 | // Shared USB HID helpers: boot-keyboard report decoding into scancode-set-1 | ||
| 3 | // bytes, plus the FIFO the drivers hand to the PS/2 decoder. | ||
| 4 | // | ||
| 5 | // Every HID keyboard (UHCI, EHCI, xHCI) feeds the same `ps2::feed_scancode` | ||
| 6 | // state machine, so a USB keyboard behaves exactly like the PS/2 one. The | ||
| 7 | // per-report diff state lives in `Keyboard` (one instance per device); the | ||
| 8 | // byte FIFO is shared because the consumer is a single scancode stream. | ||
| 9 | // --------------------------------------------------------------------------- | ||
| 10 | |||
| 11 | use core::sync::atomic::Ordering; | ||
| 12 | |||
| 13 | /// HID usage -> scancode set 1 (make code). High byte 0xE0 = E0-prefixed. | ||
| 14 | /// 0 = unmapped. Table covers the common keyboard usages (0x04..0x63). | ||
| 15 | static HID_TO_SCAN: [u16; 0x64] = { | ||
| 16 | let mut t = [0u16; 0x64]; | ||
| 17 | let mut i = 0; | ||
| 18 | while i < 0x64 { | ||
| 19 | t[i] = 0; | ||
| 20 | i += 1; | ||
| 21 | } | ||
| 22 | // Letters a-z | ||
| 23 | t[0x04] = 0x1E; | ||
| 24 | t[0x05] = 0x30; | ||
| 25 | t[0x06] = 0x2E; | ||
| 26 | t[0x07] = 0x20; | ||
| 27 | t[0x08] = 0x12; | ||
| 28 | t[0x09] = 0x21; | ||
| 29 | t[0x0A] = 0x22; | ||
| 30 | t[0x0B] = 0x23; | ||
| 31 | t[0x0C] = 0x17; | ||
| 32 | t[0x0D] = 0x24; | ||
| 33 | t[0x0E] = 0x25; | ||
| 34 | t[0x0F] = 0x26; | ||
| 35 | t[0x10] = 0x32; | ||
| 36 | t[0x11] = 0x31; | ||
| 37 | t[0x12] = 0x18; | ||
| 38 | t[0x13] = 0x19; | ||
| 39 | t[0x14] = 0x10; | ||
| 40 | t[0x15] = 0x13; | ||
| 41 | t[0x16] = 0x1F; | ||
| 42 | t[0x17] = 0x14; | ||
| 43 | t[0x18] = 0x16; | ||
| 44 | t[0x19] = 0x2F; | ||
| 45 | t[0x1A] = 0x11; | ||
| 46 | t[0x1B] = 0x2D; | ||
| 47 | t[0x1C] = 0x15; | ||
| 48 | t[0x1D] = 0x2C; | ||
| 49 | // Digits + punctuation | ||
| 50 | t[0x1E] = 0x02; | ||
| 51 | t[0x1F] = 0x03; | ||
| 52 | t[0x20] = 0x04; | ||
| 53 | t[0x21] = 0x05; | ||
| 54 | t[0x22] = 0x06; | ||
| 55 | t[0x23] = 0x07; | ||
| 56 | t[0x24] = 0x08; | ||
| 57 | t[0x25] = 0x09; | ||
| 58 | t[0x26] = 0x0A; | ||
| 59 | t[0x27] = 0x0B; | ||
| 60 | t[0x28] = 0x1C; // Enter | ||
| 61 | t[0x29] = 0x01; // Esc | ||
| 62 | t[0x2A] = 0x0E; // Backspace | ||
| 63 | t[0x2B] = 0x0F; // Tab | ||
| 64 | t[0x2C] = 0x39; // Space | ||
| 65 | t[0x2D] = 0x0C; // - | ||
| 66 | t[0x2E] = 0x0D; // = | ||
| 67 | t[0x2F] = 0x1A; // [ | ||
| 68 | t[0x30] = 0x1B; // ] | ||
| 69 | t[0x31] = 0x2B; // backslash | ||
| 70 | t[0x33] = 0x27; // ; | ||
| 71 | t[0x34] = 0x28; // ' | ||
| 72 | t[0x35] = 0x29; // ` | ||
| 73 | t[0x36] = 0x33; // , | ||
| 74 | t[0x37] = 0x34; // . | ||
| 75 | t[0x38] = 0x35; // / | ||
| 76 | t[0x39] = 0x3A; // CapsLock | ||
| 77 | // F-keys | ||
| 78 | t[0x3A] = 0x3B; // F1 | ||
| 79 | t[0x3B] = 0x3C; | ||
| 80 | t[0x3C] = 0x3D; | ||
| 81 | t[0x3D] = 0x3E; | ||
| 82 | t[0x3E] = 0x3F; | ||
| 83 | t[0x3F] = 0x40; | ||
| 84 | t[0x40] = 0x41; | ||
| 85 | t[0x41] = 0x42; | ||
| 86 | t[0x42] = 0x43; | ||
| 87 | t[0x43] = 0x44; // F10 | ||
| 88 | t[0x44] = 0xE057; // F11 | ||
| 89 | t[0x45] = 0xE058; // F12 | ||
| 90 | // Nav cluster | ||
| 91 | t[0x49] = 0xE052; // Insert | ||
| 92 | t[0x4A] = 0xE047; // Home | ||
| 93 | t[0x4B] = 0xE049; // PageUp | ||
| 94 | t[0x4C] = 0xE053; // Delete | ||
| 95 | t[0x4D] = 0xE04F; // End | ||
| 96 | t[0x4E] = 0xE051; // PageDown | ||
| 97 | t[0x4F] = 0xE04D; // Right | ||
| 98 | t[0x50] = 0xE04B; // Left | ||
| 99 | t[0x51] = 0xE050; // Down | ||
| 100 | t[0x52] = 0xE048; // Up | ||
| 101 | // Keypad | ||
| 102 | t[0x53] = 0x45; // NumLock | ||
| 103 | t[0x54] = 0xE035; // / | ||
| 104 | t[0x55] = 0x37; // * | ||
| 105 | t[0x56] = 0x4A; // - | ||
| 106 | t[0x57] = 0x4E; // + | ||
| 107 | t[0x58] = 0xE01C; // Enter | ||
| 108 | t[0x59] = 0x4F; // 1 | ||
| 109 | t[0x5A] = 0x50; // 2 | ||
| 110 | t[0x5B] = 0x51; // 3 | ||
| 111 | t[0x5C] = 0x4B; // 4 | ||
| 112 | t[0x5D] = 0x4C; // 5 | ||
| 113 | t[0x5E] = 0x4D; // 6 | ||
| 114 | t[0x5F] = 0x47; // 7 | ||
| 115 | t[0x60] = 0x48; // 8 | ||
| 116 | t[0x61] = 0x49; // 9 | ||
| 117 | t[0x62] = 0x52; // 0 | ||
| 118 | t[0x63] = 0x53; // . | ||
| 119 | t | ||
| 120 | }; | ||
| 121 | |||
| 122 | /// Modifier bit -> scancode (set 1, high byte 0xE0 = E0-prefixed). | ||
| 123 | static MOD_TO_SCAN: [u16; 8] = [ | ||
| 124 | 0x1D, // 0 LCtrl | ||
| 125 | 0x2A, // 1 LShift | ||
| 126 | 0x38, // 2 LAlt | ||
| 127 | 0xE05B, // 3 LGui | ||
| 128 | 0xE01D, // 4 RCtrl | ||
| 129 | 0x36, // 5 RShift | ||
| 130 | 0xE038, // 6 RAlt | ||
| 131 | 0xE05C, // 7 RGui | ||
| 132 | ]; | ||
| 133 | |||
| 134 | // ---- scancode FIFO (shared: one PS/2 decoder consumer) ---- | ||
| 135 | const Q_SIZE: usize = 128; | ||
| 136 | static mut Q: [u8; Q_SIZE] = [0; Q_SIZE]; | ||
| 137 | static Q_HEAD: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); | ||
| 138 | static Q_LEN: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); | ||
| 139 | |||
| 140 | /// Queue one scancode-set-1 byte (drops when the FIFO is full). | ||
| 141 | pub fn push_byte(b: u8) { | ||
| 142 | unsafe { | ||
| 143 | let h = Q_HEAD.load(Ordering::Relaxed) as usize; | ||
| 144 | let l = Q_LEN.load(Ordering::Relaxed) as usize; | ||
| 145 | if l >= Q_SIZE { | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | Q[(h + l) % Q_SIZE] = b; | ||
| 149 | Q_LEN.store((l + 1) as u32, Ordering::Relaxed); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | /// Pop one queued scancode byte (callers feed it to `ps2::feed_scancode`). | ||
| 154 | pub fn pop_byte() -> Option<u8> { | ||
| 155 | unsafe { | ||
| 156 | let l = Q_LEN.load(Ordering::Relaxed) as usize; | ||
| 157 | if l == 0 { | ||
| 158 | return None; | ||
| 159 | } | ||
| 160 | let h = Q_HEAD.load(Ordering::Relaxed) as usize; | ||
| 161 | let b = Q[h]; | ||
| 162 | Q_HEAD.store(((h + 1) % Q_SIZE) as u32, Ordering::Relaxed); | ||
| 163 | Q_LEN.store((l - 1) as u32, Ordering::Relaxed); | ||
| 164 | Some(b) | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | /// Push the make (press) or break (release) scancode sequence for a | ||
| 169 | /// scancode-map entry (0 = unmapped, 0x00XX = plain, 0xE0XX = E0-prefixed). | ||
| 170 | pub fn push_scancode(scan: u16, press: bool) { | ||
| 171 | if scan == 0 { | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | if scan & 0xFF00 == 0xE000 { | ||
| 175 | push_byte(0xE0); | ||
| 176 | let code = (scan & 0xFF) as u8; | ||
| 177 | push_byte(if press { code } else { code | 0x80 }); | ||
| 178 | } else { | ||
| 179 | let code = scan as u8; | ||
| 180 | push_byte(if press { code } else { code | 0x80 }); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | /// Per-device boot-keyboard report differ. Boot protocol reports are | ||
| 185 | /// 8 bytes: modifiers, reserved, 6 usage codes. | ||
| 186 | pub struct Keyboard { | ||
| 187 | prev: [u8; 8], | ||
| 188 | } | ||
| 189 | |||
| 190 | impl Keyboard { | ||
| 191 | pub const fn new() -> Self { | ||
| 192 | Self { prev: [0; 8] } | ||
| 193 | } | ||
| 194 | |||
| 195 | /// Diff `report` against the previous one and queue make/break bytes. | ||
| 196 | pub fn diff(&mut self, report: &[u8]) { | ||
| 197 | let mut rep = [0u8; 8]; | ||
| 198 | for (i, b) in rep.iter_mut().enumerate() { | ||
| 199 | *b = report.get(i).copied().unwrap_or(0); | ||
| 200 | } | ||
| 201 | let new_mods = rep[0]; | ||
| 202 | let old_mods = self.prev[0]; | ||
| 203 | for bit in 0..8 { | ||
| 204 | let new_set = new_mods & (1 << bit) != 0; | ||
| 205 | let old_set = old_mods & (1 << bit) != 0; | ||
| 206 | if new_set != old_set { | ||
| 207 | push_scancode(MOD_TO_SCAN[bit], new_set); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | let new_keys = &rep[2..8]; | ||
| 211 | let old_keys = &self.prev[2..8]; | ||
| 212 | // Releases first (old keys not in the new set). | ||
| 213 | for &k in old_keys { | ||
| 214 | if k == 0 || new_keys.contains(&k) { | ||
| 215 | continue; | ||
| 216 | } | ||
| 217 | if (k as usize) < HID_TO_SCAN.len() { | ||
| 218 | push_scancode(HID_TO_SCAN[k as usize], false); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | // Then presses (new keys not in the old set). | ||
| 222 | for &k in new_keys { | ||
| 223 | if k == 0 || old_keys.contains(&k) { | ||
| 224 | continue; | ||
| 225 | } | ||
| 226 | if (k as usize) < HID_TO_SCAN.len() { | ||
| 227 | push_scancode(HID_TO_SCAN[k as usize], true); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | self.prev = rep; | ||
| 231 | } | ||
| 232 | } | ||
diff --git a/rsnix/src/lib.rs b/rsnix/src/lib.rs index 325932a..b4307a3 100644 --- a/rsnix/src/lib.rs +++ b/rsnix/src/lib.rs | |||
| @@ -11,6 +11,7 @@ pub mod font; | |||
| 11 | pub mod fs; | 11 | pub mod fs; |
| 12 | pub mod gdt; | 12 | pub mod gdt; |
| 13 | pub mod gop; | 13 | pub mod gop; |
| 14 | pub mod hid; | ||
| 14 | pub mod interrupts; | 15 | pub mod interrupts; |
| 15 | pub mod klog; | 16 | pub mod klog; |
| 16 | pub mod load; | 17 | pub mod load; |
diff --git a/rsnix/src/uhci.rs b/rsnix/src/uhci.rs index 87ec9c6..988db72 100644 --- a/rsnix/src/uhci.rs +++ b/rsnix/src/uhci.rs | |||
| @@ -133,12 +133,9 @@ const OFF_CFG: usize = 0x300; // config descriptor (256 B) | |||
| 133 | const OFF_KBD_REPORT: usize = 0x500; // 8 B | 133 | const OFF_KBD_REPORT: usize = 0x500; // 8 B |
| 134 | const OFF_MOUSE_REPORT: usize = 0x520; // 8 B | 134 | const OFF_MOUSE_REPORT: usize = 0x520; // 8 B |
| 135 | 135 | ||
| 136 | // Keyboard: previous report + pending scancode FIFO (fed to ps2 decoder). | 136 | // Keyboard: per-device HID report diff state. Scancode bytes go to the |
| 137 | static mut KBD_PREV: [u8; 8] = [0; 8]; | 137 | // shared FIFO in `hid.rs` (drained by the single PS/2 decoder). |
| 138 | const KBDQ_SIZE: usize = 64; | 138 | static mut KBD: crate::hid::Keyboard = crate::hid::Keyboard::new(); |
| 139 | static mut KBDQ: [u8; KBDQ_SIZE] = [0; KBDQ_SIZE]; | ||
| 140 | static KBDQ_HEAD: AtomicU32 = AtomicU32::new(0); | ||
| 141 | static KBDQ_LEN: AtomicU32 = AtomicU32::new(0); | ||
| 142 | 139 | ||
| 143 | // ---- port I/O ---- | 140 | // ---- port I/O ---- |
| 144 | #[inline] | 141 | #[inline] |
| @@ -495,7 +492,10 @@ unsafe fn enumerate_port(p: usize, want: u8) -> bool { | |||
| 495 | } | 492 | } |
| 496 | 493 | ||
| 497 | // 6. Boot protocol + no idle. Some devices stall these; tolerate. | 494 | // 6. Boot protocol + no idle. Some devices stall these; tolerate. |
| 498 | let req = ctrl_req(RT_CLASS_IFACE, REQ_SET_PROTOCOL, 1, ep.iface as u16, 0); | 495 | // wValue 0 = boot protocol: guarantees the 3-byte mouse / 8-byte |
| 496 | // keyboard report layout the drivers parse. (wValue 1 would be | ||
| 497 | // report protocol, where the layout is device-defined.) | ||
| 498 | let req = ctrl_req(RT_CLASS_IFACE, REQ_SET_PROTOCOL, 0, ep.iface as u16, 0); | ||
| 499 | if ctl_xfer(dev, mps0, low_speed, &req, false, core::ptr::null_mut(), 0) < 0 { | 499 | if ctl_xfer(dev, mps0, low_speed, &req, false, core::ptr::null_mut(), 0) < 0 { |
| 500 | crate::serial_println!("uhci: set-protocol stalled on port {}", p); | 500 | crate::serial_println!("uhci: set-protocol stalled on port {}", p); |
| 501 | } | 501 | } |
| @@ -618,211 +618,10 @@ unsafe fn arm_device(want: u8) -> bool { | |||
| 618 | } | 618 | } |
| 619 | 619 | ||
| 620 | // --------------------------------------------------------------------------- | 620 | // --------------------------------------------------------------------------- |
| 621 | // Keyboard: HID report -> scancode-set-1 make/break bytes -> ps2 decoder | 621 | // Keyboard: HID reports feed the shared scancode FIFO (`hid.rs`), drained by |
| 622 | // try_poll_key through the PS/2 decoder. | ||
| 622 | // --------------------------------------------------------------------------- | 623 | // --------------------------------------------------------------------------- |
| 623 | 624 | ||
| 624 | /// HID usage -> scancode set 1 (make code). High byte 0xE0 = E0-prefixed. | ||
| 625 | /// 0 = unmapped. Table covers the common keyboard usages (0x04..0x63). | ||
| 626 | static HID_TO_SCAN: [u16; 0x64] = { | ||
| 627 | let mut t = [0u16; 0x64]; | ||
| 628 | let mut i = 0; | ||
| 629 | while i < 0x64 { | ||
| 630 | t[i] = 0; | ||
| 631 | i += 1; | ||
| 632 | } | ||
| 633 | // Letters a-z | ||
| 634 | t[0x04] = 0x1E; | ||
| 635 | t[0x05] = 0x30; | ||
| 636 | t[0x06] = 0x2E; | ||
| 637 | t[0x07] = 0x20; | ||
| 638 | t[0x08] = 0x12; | ||
| 639 | t[0x09] = 0x21; | ||
| 640 | t[0x0A] = 0x22; | ||
| 641 | t[0x0B] = 0x23; | ||
| 642 | t[0x0C] = 0x17; | ||
| 643 | t[0x0D] = 0x24; | ||
| 644 | t[0x0E] = 0x25; | ||
| 645 | t[0x0F] = 0x26; | ||
| 646 | t[0x10] = 0x32; | ||
| 647 | t[0x11] = 0x31; | ||
| 648 | t[0x12] = 0x18; | ||
| 649 | t[0x13] = 0x19; | ||
| 650 | t[0x14] = 0x10; | ||
| 651 | t[0x15] = 0x13; | ||
| 652 | t[0x16] = 0x1F; | ||
| 653 | t[0x17] = 0x14; | ||
| 654 | t[0x18] = 0x16; | ||
| 655 | t[0x19] = 0x2F; | ||
| 656 | t[0x1A] = 0x11; | ||
| 657 | t[0x1B] = 0x2D; | ||
| 658 | t[0x1C] = 0x15; | ||
| 659 | t[0x1D] = 0x2C; | ||
| 660 | // Digits + punctuation | ||
| 661 | t[0x1E] = 0x02; | ||
| 662 | t[0x1F] = 0x03; | ||
| 663 | t[0x20] = 0x04; | ||
| 664 | t[0x21] = 0x05; | ||
| 665 | t[0x22] = 0x06; | ||
| 666 | t[0x23] = 0x07; | ||
| 667 | t[0x24] = 0x08; | ||
| 668 | t[0x25] = 0x09; | ||
| 669 | t[0x26] = 0x0A; | ||
| 670 | t[0x27] = 0x0B; | ||
| 671 | t[0x28] = 0x1C; // Enter | ||
| 672 | t[0x29] = 0x01; // Esc | ||
| 673 | t[0x2A] = 0x0E; // Backspace | ||
| 674 | t[0x2B] = 0x0F; // Tab | ||
| 675 | t[0x2C] = 0x39; // Space | ||
| 676 | t[0x2D] = 0x0C; // - | ||
| 677 | t[0x2E] = 0x0D; // = | ||
| 678 | t[0x2F] = 0x1A; // [ | ||
| 679 | t[0x30] = 0x1B; // ] | ||
| 680 | t[0x31] = 0x2B; // backslash | ||
| 681 | t[0x33] = 0x27; // ; | ||
| 682 | t[0x34] = 0x28; // ' | ||
| 683 | t[0x35] = 0x29; // ` | ||
| 684 | t[0x36] = 0x33; // , | ||
| 685 | t[0x37] = 0x34; // . | ||
| 686 | t[0x38] = 0x35; // / | ||
| 687 | t[0x39] = 0x3A; // CapsLock | ||
| 688 | // F-keys | ||
| 689 | t[0x3A] = 0x3B; // F1 | ||
| 690 | t[0x3B] = 0x3C; | ||
| 691 | t[0x3C] = 0x3D; | ||
| 692 | t[0x3D] = 0x3E; | ||
| 693 | t[0x3E] = 0x3F; | ||
| 694 | t[0x3F] = 0x40; | ||
| 695 | t[0x40] = 0x41; | ||
| 696 | t[0x41] = 0x42; | ||
| 697 | t[0x42] = 0x43; | ||
| 698 | t[0x43] = 0x44; // F10 | ||
| 699 | t[0x44] = 0xE057; // F11 | ||
| 700 | t[0x45] = 0xE058; // F12 | ||
| 701 | // Nav cluster | ||
| 702 | t[0x49] = 0xE052; // Insert | ||
| 703 | t[0x4A] = 0xE047; // Home | ||
| 704 | t[0x4B] = 0xE049; // PageUp | ||
| 705 | t[0x4C] = 0xE053; // Delete | ||
| 706 | t[0x4D] = 0xE04F; // End | ||
| 707 | t[0x4E] = 0xE051; // PageDown | ||
| 708 | t[0x4F] = 0xE04D; // Right | ||
| 709 | t[0x50] = 0xE04B; // Left | ||
| 710 | t[0x51] = 0xE050; // Down | ||
| 711 | t[0x52] = 0xE048; // Up | ||
| 712 | // Keypad | ||
| 713 | t[0x53] = 0x45; // NumLock | ||
| 714 | t[0x54] = 0xE035; // / | ||
| 715 | t[0x55] = 0x37; // * | ||
| 716 | t[0x56] = 0x4A; // - | ||
| 717 | t[0x57] = 0x4E; // + | ||
| 718 | t[0x58] = 0xE01C; // Enter | ||
| 719 | t[0x59] = 0x4F; // 1 | ||
| 720 | t[0x5A] = 0x50; // 2 | ||
| 721 | t[0x5B] = 0x51; // 3 | ||
| 722 | t[0x5C] = 0x4B; // 4 | ||
| 723 | t[0x5D] = 0x4C; // 5 | ||
| 724 | t[0x5E] = 0x4D; // 6 | ||
| 725 | t[0x5F] = 0x47; // 7 | ||
| 726 | t[0x60] = 0x48; // 8 | ||
| 727 | t[0x61] = 0x49; // 9 | ||
| 728 | t[0x62] = 0x52; // 0 | ||
| 729 | t[0x63] = 0x53; // . | ||
| 730 | t | ||
| 731 | }; | ||
| 732 | |||
| 733 | /// Modifier bit -> scancode (set 1, high byte 0xE0 = E0-prefixed). | ||
| 734 | static MOD_TO_SCAN: [u16; 8] = [ | ||
| 735 | 0x1D, // 0 LCtrl | ||
| 736 | 0x2A, // 1 LShift | ||
| 737 | 0x38, // 2 LAlt | ||
| 738 | 0xE05B, // 3 LGui | ||
| 739 | 0xE01D, // 4 RCtrl | ||
| 740 | 0x36, // 5 RShift | ||
| 741 | 0xE038, // 6 RAlt | ||
| 742 | 0xE05C, // 7 RGui | ||
| 743 | ]; | ||
| 744 | |||
| 745 | fn kbdq_push(b: u8) { | ||
| 746 | unsafe { | ||
| 747 | let h = KBDQ_HEAD.load(Ordering::Relaxed) as usize; | ||
| 748 | let l = KBDQ_LEN.load(Ordering::Relaxed) as usize; | ||
| 749 | if l >= KBDQ_SIZE { | ||
| 750 | return; | ||
| 751 | } | ||
| 752 | KBDQ[(h + l) % KBDQ_SIZE] = b; | ||
| 753 | KBDQ_LEN.store((l + 1) as u32, Ordering::Relaxed); | ||
| 754 | } | ||
| 755 | } | ||
| 756 | fn kbdq_pop() -> Option<u8> { | ||
| 757 | unsafe { | ||
| 758 | let l = KBDQ_LEN.load(Ordering::Relaxed) as usize; | ||
| 759 | if l == 0 { | ||
| 760 | return None; | ||
| 761 | } | ||
| 762 | let h = KBDQ_HEAD.load(Ordering::Relaxed) as usize; | ||
| 763 | let b = KBDQ[h]; | ||
| 764 | KBDQ_HEAD.store(((h + 1) % KBDQ_SIZE) as u32, Ordering::Relaxed); | ||
| 765 | KBDQ_LEN.store((l - 1) as u32, Ordering::Relaxed); | ||
| 766 | Some(b) | ||
| 767 | } | ||
| 768 | } | ||
| 769 | |||
| 770 | /// Push the make (press) or break (release) scancode sequence for a | ||
| 771 | /// scancode-map entry (0 = unmapped, 0x00XX = plain, 0xE0XX = E0-prefixed). | ||
| 772 | fn push_scancode(scan: u16, press: bool) { | ||
| 773 | if scan == 0 { | ||
| 774 | return; | ||
| 775 | } | ||
| 776 | if scan & 0xFF00 == 0xE000 { | ||
| 777 | kbdq_push(0xE0); | ||
| 778 | let code = (scan & 0xFF) as u8; | ||
| 779 | kbdq_push(if press { code } else { code | 0x80 }); | ||
| 780 | } else { | ||
| 781 | let code = scan as u8; | ||
| 782 | kbdq_push(if press { code } else { code | 0x80 }); | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | /// Diff the completed HID report against the previous one and queue the | ||
| 787 | /// scancode transitions (make/break) for the shared PS/2 decoder. | ||
| 788 | unsafe fn diff_report(report: &[u8]) { | ||
| 789 | unsafe { | ||
| 790 | let prev = &mut *core::ptr::addr_of_mut!(KBD_PREV); | ||
| 791 | let new_mods = report[0]; | ||
| 792 | let old_mods = prev[0]; | ||
| 793 | for bit in 0..8 { | ||
| 794 | let new_set = new_mods & (1 << bit) != 0; | ||
| 795 | let old_set = old_mods & (1 << bit) != 0; | ||
| 796 | if new_set != old_set { | ||
| 797 | push_scancode(MOD_TO_SCAN[bit], new_set); | ||
| 798 | } | ||
| 799 | } | ||
| 800 | let new_keys = &report[2..8]; | ||
| 801 | let old_keys = &prev[2..8]; | ||
| 802 | // Releases first (old keys not in new set). | ||
| 803 | for &k in old_keys { | ||
| 804 | if k == 0 || new_keys.contains(&k) { | ||
| 805 | continue; | ||
| 806 | } | ||
| 807 | if k as usize >= HID_TO_SCAN.len() { | ||
| 808 | continue; | ||
| 809 | } | ||
| 810 | push_scancode(HID_TO_SCAN[k as usize], false); | ||
| 811 | } | ||
| 812 | // Then presses (new keys not in the old set). | ||
| 813 | for &k in new_keys { | ||
| 814 | if k == 0 || old_keys.contains(&k) { | ||
| 815 | continue; | ||
| 816 | } | ||
| 817 | if k as usize >= HID_TO_SCAN.len() { | ||
| 818 | continue; | ||
| 819 | } | ||
| 820 | push_scancode(HID_TO_SCAN[k as usize], true); | ||
| 821 | } | ||
| 822 | prev.copy_from_slice(report); | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 826 | /// Re-arm a completed interrupt-IN TD (one-outstanding report pattern). | 625 | /// Re-arm a completed interrupt-IN TD (one-outstanding report pattern). |
| 827 | unsafe fn rearm_td(qho: usize, tdo: usize, toggle: u32, ls: bool, mps: usize, explen: u32) { | 626 | unsafe fn rearm_td(qho: usize, tdo: usize, toggle: u32, ls: bool, mps: usize, explen: u32) { |
| 828 | unsafe { | 627 | unsafe { |
| @@ -998,7 +797,7 @@ pub fn init() -> bool { | |||
| 998 | pub fn try_poll_key() -> Option<crate::ps2::KeyEvent> { | 797 | pub fn try_poll_key() -> Option<crate::ps2::KeyEvent> { |
| 999 | unsafe { | 798 | unsafe { |
| 1000 | // Fast path: pending scancodes first. | 799 | // Fast path: pending scancodes first. |
| 1001 | if let Some(b) = kbdq_pop() { | 800 | if let Some(b) = crate::hid::pop_byte() { |
| 1002 | return crate::ps2::feed_scancode(b); | 801 | return crate::ps2::feed_scancode(b); |
| 1003 | } | 802 | } |
| 1004 | if KBD_ARMED.load(Ordering::Relaxed) { | 803 | if KBD_ARMED.load(Ordering::Relaxed) { |
| @@ -1016,7 +815,8 @@ pub fn try_poll_key() -> Option<crate::ps2::KeyEvent> { | |||
| 1016 | for (i, b) in report.iter_mut().enumerate() { | 815 | for (i, b) in report.iter_mut().enumerate() { |
| 1017 | *b = core::ptr::read_volatile(rep.add(i)); | 816 | *b = core::ptr::read_volatile(rep.add(i)); |
| 1018 | } | 817 | } |
| 1019 | diff_report(&report); | 818 | let kbd = &mut *core::ptr::addr_of_mut!(KBD); |
| 819 | kbd.diff(&report); | ||
| 1020 | let tog = KBD_TOGGLE.load(Ordering::Relaxed) ^ 1; | 820 | let tog = KBD_TOGGLE.load(Ordering::Relaxed) ^ 1; |
| 1021 | KBD_TOGGLE.store(tog, Ordering::Relaxed); | 821 | KBD_TOGGLE.store(tog, Ordering::Relaxed); |
| 1022 | rearm_td( | 822 | rearm_td( |
| @@ -1027,7 +827,7 @@ pub fn try_poll_key() -> Option<crate::ps2::KeyEvent> { | |||
| 1027 | KBD_MPS.load(Ordering::Relaxed) as usize, | 827 | KBD_MPS.load(Ordering::Relaxed) as usize, |
| 1028 | 8, | 828 | 8, |
| 1029 | ); | 829 | ); |
| 1030 | return kbdq_pop().and_then(crate::ps2::feed_scancode); | 830 | return crate::hid::pop_byte().and_then(crate::ps2::feed_scancode); |
| 1031 | } | 831 | } |
| 1032 | return None; | 832 | return None; |
| 1033 | } | 833 | } |
| @@ -1039,7 +839,7 @@ pub fn try_poll_key() -> Option<crate::ps2::KeyEvent> { | |||
| 1039 | let _ = arm_device(1); | 839 | let _ = arm_device(1); |
| 1040 | } | 840 | } |
| 1041 | } | 841 | } |
| 1042 | kbdq_pop().and_then(crate::ps2::feed_scancode) | 842 | crate::hid::pop_byte().and_then(crate::ps2::feed_scancode) |
| 1043 | } | 843 | } |
| 1044 | } | 844 | } |
| 1045 | 845 | ||
