1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
// ---------------------------------------------------------------------------
// 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<u8> {
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.
#[derive(Clone, Copy)]
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;
}
}
|