Skip to main content

strat9_kernel/hardware/usb/
hid.rs

1// USB HID (Human Interface Device) Driver
2// Supports boot protocol keyboards and mice
3//
4// Features:
5// - Boot protocol keyboard support
6// - Boot protocol mouse support
7// - Event queue for key presses and mouse movements
8// - PS/2 to USB keycode translation
9// - Interrupt transfer polling via xHCI
10// - Unification with PS/2: events feed into the same keyboard/mouse buffers
11//
12// Inspired by Redox usbhid, Asterinas input subsystem, Maestro device manager.
13
14#![allow(dead_code)]
15
16use crate::arch::x86_64::{keyboard, mouse};
17use alloc::{sync::Arc, vec::Vec};
18use core::sync::atomic::{AtomicBool, Ordering};
19use spin::Mutex;
20
21pub const HID_BOOT_KEYBOARD: u8 = 0x01;
22pub const HID_BOOT_MOUSE: u8 = 0x02;
23
24const KBD_REPORT_SIZE: usize = 8;
25const MOUSE_REPORT_SIZE: usize = 4;
26
27#[derive(Clone, Copy, Debug)]
28pub struct KeyEvent {
29    pub keycode: u8,
30    pub pressed: bool,
31    pub modifiers: u8,
32}
33
34#[derive(Clone, Copy, Debug)]
35pub struct MouseEvent {
36    pub dx: i8,
37    pub dy: i8,
38    pub dz: i8,
39    pub buttons: u8,
40}
41
42const USB_TO_PS2: [u8; 128] = [
43    0x00, 0x00, 0x00, 0x00, 0x1C, 0x32, 0x21, 0x23, 0x1D, 0x24, 0x2B, 0x34, 0x33, 0x43, 0x35, 0x0E,
44    0x15, 0x16, 0x17, 0x1C, 0x18, 0x19, 0x14, 0x1A, 0x1B, 0x1D, 0x1E, 0x21, 0x22, 0x23, 0x24, 0x2B,
45    0x29, 0x2F, 0x2E, 0x30, 0x20, 0x31, 0x32, 0x33, 0x2C, 0x2D, 0x11, 0x12, 0x13, 0x3F, 0x3E, 0x46,
46    0x45, 0x5D, 0x4C, 0x36, 0x4A, 0x55, 0x37, 0x4E, 0x57, 0x5E, 0x5C, 0x41, 0x52, 0x4D, 0x4B, 0x5B,
47    0x5A, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
48    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51];
52
53fn usb_to_ps2(keycode: u8) -> u8 {
54    if keycode < USB_TO_PS2.len() as u8 {
55        USB_TO_PS2[keycode as usize]
56    } else {
57        0x00
58    }
59}
60
61pub struct HidKeyboard {
62    port: usize,
63    slot_id: u8,
64    interface: u8,
65    endpoint: u8,
66    max_packet: u16,
67    interval: u8,
68    event_queue: Vec<KeyEvent>,
69    last_report: [u8; KBD_REPORT_SIZE],
70    report_buf: *mut u8,
71}
72
73unsafe impl Send for HidKeyboard {}
74unsafe impl Sync for HidKeyboard {}
75
76impl HidKeyboard {
77    pub fn new(
78        port: usize,
79        slot_id: u8,
80        interface: u8,
81        endpoint: u8,
82        max_packet: u16,
83        interval: u8,
84    ) -> Self {
85        Self {
86            port,
87            slot_id,
88            interface,
89            endpoint,
90            max_packet,
91            interval,
92            event_queue: Vec::new(),
93            last_report: [0; KBD_REPORT_SIZE],
94            report_buf: core::ptr::null_mut(),
95        }
96    }
97
98    pub fn read_event(&mut self) -> Option<KeyEvent> {
99        self.event_queue.pop()
100    }
101
102    pub fn process_report(&mut self, report: &[u8]) {
103        if report.len() < KBD_REPORT_SIZE {
104            return;
105        }
106        let modifiers = report[0];
107
108        for i in 2..8 {
109            let keycode = report[i];
110            if keycode == 0 {
111                continue;
112            }
113            let was_pressed = self.last_report[2..8].contains(&keycode);
114            if !was_pressed {
115                self.event_queue.push(KeyEvent {
116                    keycode: usb_to_ps2(keycode),
117                    pressed: true,
118                    modifiers,
119                });
120            }
121        }
122
123        for i in 2..8 {
124            let keycode = self.last_report[i];
125            if keycode != 0 && !report[2..8].contains(&keycode) {
126                self.event_queue.push(KeyEvent {
127                    keycode: usb_to_ps2(keycode),
128                    pressed: false,
129                    modifiers,
130                });
131            }
132        }
133
134        for i in 0..8 {
135            self.last_report[i] = report[i];
136        }
137    }
138
139    pub fn is_modifier_pressed(&self, modifier: u8) -> bool {
140        self.last_report[0] & modifier != 0
141    }
142
143    pub fn drain_into_unified(&mut self) {
144        while let Some(ev) = self.event_queue.pop() {
145            keyboard::inject_hid_scancode(ev.keycode, ev.pressed);
146        }
147    }
148}
149
150pub struct HidMouse {
151    port: usize,
152    slot_id: u8,
153    interface: u8,
154    endpoint: u8,
155    max_packet: u16,
156    interval: u8,
157    event_queue: Vec<MouseEvent>,
158    last_buttons: u8,
159    report_buf: *mut u8,
160}
161
162unsafe impl Send for HidMouse {}
163unsafe impl Sync for HidMouse {}
164
165impl HidMouse {
166    pub fn new(
167        port: usize,
168        slot_id: u8,
169        interface: u8,
170        endpoint: u8,
171        max_packet: u16,
172        interval: u8,
173    ) -> Self {
174        Self {
175            port,
176            slot_id,
177            interface,
178            endpoint,
179            max_packet,
180            interval,
181            event_queue: Vec::new(),
182            last_buttons: 0,
183            report_buf: core::ptr::null_mut(),
184        }
185    }
186
187    pub fn read_event(&mut self) -> Option<MouseEvent> {
188        self.event_queue.pop()
189    }
190
191    pub fn process_report(&mut self, report: &[u8]) {
192        if report.len() < 3 {
193            return;
194        }
195
196        let buttons = report[0];
197        let dx = report[1] as i8;
198        let dy = report[2] as i8;
199        let dz = if report.len() > 3 { report[3] as i8 } else { 0 };
200
201        for i in 0..5 {
202            let mask = 1 << i;
203            let was_pressed = self.last_buttons & mask != 0;
204            let is_pressed = buttons & mask != 0;
205
206            if was_pressed != is_pressed {
207                self.event_queue.push(MouseEvent {
208                    dx: 0,
209                    dy: 0,
210                    dz: 0,
211                    buttons: if is_pressed { mask } else { 0 },
212                });
213            }
214        }
215
216        if dx != 0 || dy != 0 || dz != 0 {
217            self.event_queue.push(MouseEvent {
218                dx,
219                dy,
220                dz,
221                buttons,
222            });
223        }
224
225        self.last_buttons = buttons;
226    }
227
228    pub fn is_button_pressed(&self, button: u8) -> bool {
229        self.last_buttons & (1 << button) != 0
230    }
231
232    pub fn drain_into_unified(&mut self) {
233        while let Some(ev) = self.event_queue.pop() {
234            let left = ev.buttons & 0x01 != 0;
235            let right = ev.buttons & 0x02 != 0;
236            let middle = ev.buttons & 0x04 != 0;
237            mouse::push_event_from_hid(ev.dx as i16, ev.dy as i16, ev.dz, left, right, middle);
238        }
239    }
240}
241
242static KEYBOARDS: Mutex<Vec<Arc<Mutex<HidKeyboard>>>> = Mutex::new(Vec::new());
243static MICE: Mutex<Vec<Arc<Mutex<HidMouse>>>> = Mutex::new(Vec::new());
244static HID_INITIALIZED: AtomicBool = AtomicBool::new(false);
245
246pub fn init() {
247    log::info!("[USB-HID] Initializing HID drivers...");
248    HID_INITIALIZED.store(true, Ordering::SeqCst);
249    log::info!(
250        "[USB-HID] Initialized: {} keyboard(s), {} mouse/mice",
251        KEYBOARDS.lock().len(),
252        MICE.lock().len()
253    );
254}
255
256pub fn enumerate_device(port: usize, slot_id: u8, dev_desc: &[u8; 18]) {
257    let dev_class = dev_desc[4];
258
259    if dev_class == 0x03 {
260        let protocol = dev_desc[6];
261        log::info!(
262            "[USB-HID] HID device: port={} slot={} class=03 protocol={:02x}",
263            port,
264            slot_id,
265            protocol
266        );
267
268        if let Some(controller_arc) = crate::hardware::usb::xhci::get_controller(0) {
269            let mut controller = controller_arc.lock();
270
271            if protocol == 1 {
272                controller.set_protocol(port as u8, 0, 0).ok();
273            } else if protocol == 2 {
274                controller.set_protocol(port as u8, 0, 1).ok();
275            }
276
277            let mut config_desc = [0u8; 256];
278            if controller
279                .get_configuration_descriptor(slot_id, 0, &mut config_desc, 9)
280                .is_ok()
281            {
282                let total_len = u16::from_le_bytes([config_desc[2], config_desc[3]]) as usize;
283                if total_len > 9 && total_len <= 256 {
284                    controller
285                        .get_configuration_descriptor(slot_id, 0, &mut config_desc, total_len)
286                        .ok();
287                }
288
289                let mut offset = 9;
290                while offset + 9 <= total_len {
291                    let b_length = config_desc[offset];
292                    let b_descriptor_type = config_desc[offset + 1];
293                    if b_length < 9 || offset + b_length as usize > total_len {
294                        break;
295                    }
296                    if b_descriptor_type == 4 {
297                        let b_interface_class = config_desc[offset + 5];
298                        let b_interface_protocol = config_desc[offset + 7];
299
300                        if b_interface_class == 0x03 {
301                            let mut ep_offset = offset + 9;
302                            while ep_offset + 7 <= offset + b_length as usize {
303                                let ep_b_length = config_desc[ep_offset];
304                                let ep_b_descriptor_type = config_desc[ep_offset + 1];
305                                if ep_b_length < 7 || ep_b_descriptor_type != 5 {
306                                    break;
307                                }
308                                let ep_addr = config_desc[ep_offset + 2];
309                                let ep_max_packet = u16::from_le_bytes([
310                                    config_desc[ep_offset + 4],
311                                    config_desc[ep_offset + 5],
312                                ]);
313                                let ep_interval = config_desc[ep_offset + 6];
314
315                                if (ep_addr & 0x80) != 0 {
316                                    let ep_num = ep_addr & 0x0F;
317                                    let ep_type = 7;
318
319                                    controller
320                                        .setup_endpoint(
321                                            slot_id,
322                                            ep_num,
323                                            ep_max_packet as u32,
324                                            ep_type,
325                                            ep_interval as u32,
326                                            0,
327                                        )
328                                        .ok();
329
330                                    let buf_size = ep_max_packet as usize;
331                                    if let Ok((_buf_virt, _buf_phys)) =
332                                        controller.alloc_interrupt_buffer(slot_id, ep_num, buf_size)
333                                    {
334                                        if b_interface_protocol == 1 {
335                                            let mut keyboard = HidKeyboard::new(
336                                                port,
337                                                slot_id,
338                                                config_desc[offset + 2],
339                                                ep_addr,
340                                                ep_max_packet,
341                                                ep_interval,
342                                            );
343                                            keyboard.report_buf = _buf_virt;
344                                            log::info!(
345                                                "[USB-HID] Keyboard: port={} slot={} ep={:02x} max_pkt={} interval={}",
346                                                port,
347                                                slot_id,
348                                                ep_addr,
349                                                ep_max_packet,
350                                                ep_interval
351                                            );
352                                            KEYBOARDS.lock().push(Arc::new(Mutex::new(keyboard)));
353
354                                            controller
355                                                .submit_interrupt_transfer(slot_id, ep_num)
356                                                .ok();
357                                        } else if b_interface_protocol == 2 {
358                                            let mut mouse_dev = HidMouse::new(
359                                                port,
360                                                slot_id,
361                                                config_desc[offset + 2],
362                                                ep_addr,
363                                                ep_max_packet,
364                                                ep_interval,
365                                            );
366                                            mouse_dev.report_buf = _buf_virt;
367                                            log::info!(
368                                                "[USB-HID] Mouse: port={} slot={} ep={:02x} max_pkt={} interval={}",
369                                                port,
370                                                slot_id,
371                                                ep_addr,
372                                                ep_max_packet,
373                                                ep_interval
374                                            );
375                                            MICE.lock().push(Arc::new(Mutex::new(mouse_dev)));
376
377                                            controller
378                                                .submit_interrupt_transfer(slot_id, ep_num)
379                                                .ok();
380                                        }
381                                    }
382                                }
383                                ep_offset += ep_b_length as usize;
384                            }
385                        }
386                    }
387                    offset += b_length as usize;
388                }
389            }
390
391            controller.set_configuration(slot_id, 1).ok();
392        }
393    } else {
394        log::info!(
395            "[USB-HID] Non-HID device: port={} slot={} class={:02x}",
396            port,
397            slot_id,
398            dev_class
399        );
400    }
401}
402
403pub fn receive_interrupt_report(slot_id: u8, ep_id: u8, buf: *const u8, len: usize) {
404    if buf.is_null() || len == 0 {
405        return;
406    }
407
408    let report = unsafe { core::slice::from_raw_parts(buf, len) };
409
410    for kbd in KEYBOARDS.lock().iter() {
411        let mut k = kbd.lock();
412        if k.slot_id == slot_id && (k.endpoint & 0x0F) == ep_id {
413            k.process_report(report);
414            k.drain_into_unified();
415            return;
416        }
417    }
418
419    for m in MICE.lock().iter() {
420        let mut dev = m.lock();
421        if dev.slot_id == slot_id && (dev.endpoint & 0x0F) == ep_id {
422            dev.process_report(report);
423            dev.drain_into_unified();
424            return;
425        }
426    }
427}
428
429pub fn get_keyboard(index: usize) -> Option<Arc<Mutex<HidKeyboard>>> {
430    KEYBOARDS.lock().get(index).cloned()
431}
432
433pub fn get_mouse(index: usize) -> Option<Arc<Mutex<HidMouse>>> {
434    MICE.lock().get(index).cloned()
435}
436
437pub fn keyboard_count() -> usize {
438    KEYBOARDS.lock().len()
439}
440
441pub fn mouse_count() -> usize {
442    MICE.lock().len()
443}
444
445pub fn is_available() -> bool {
446    HID_INITIALIZED.load(Ordering::Relaxed)
447}
448
449pub fn poll_all() {
450    for kbd in KEYBOARDS.lock().iter() {
451        let mut k = kbd.lock();
452        k.drain_into_unified();
453    }
454    for m in MICE.lock().iter() {
455        let mut dev = m.lock();
456        dev.drain_into_unified();
457    }
458}
459
460pub fn notify_transfer_complete(_slot_id: u8, _ep_id: u8) {
461    poll_all();
462}