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
10#![allow(dead_code)]
11
12use crate::hardware::usb::xhci::XhciController;
13use alloc::{sync::Arc, vec::Vec};
14use core::sync::atomic::{AtomicBool, Ordering};
15use spin::Mutex;
16
17pub const HID_BOOT_KEYBOARD: u8 = 0x01;
18pub const HID_BOOT_MOUSE: u8 = 0x02;
19
20// USB HID Boot Keyboard Report size (8 bytes)
21const KBD_REPORT_SIZE: usize = 8;
22
23// USB HID Boot Mouse Report size (3 bytes for basic mice)
24const MOUSE_REPORT_SIZE: usize = 3;
25
26// Modifier keys
27const MOD_LCTRL: u8 = 0x01;
28const MOD_LSHIFT: u8 = 0x02;
29const MOD_LALT: u8 = 0x04;
30const MOD_LGUI: u8 = 0x08;
31const MOD_RCTRL: u8 = 0x10;
32const MOD_RSHIFT: u8 = 0x20;
33const MOD_RALT: u8 = 0x40;
34const MOD_RGUI: u8 = 0x80;
35
36#[derive(Clone, Copy, Debug)]
37pub struct KeyEvent {
38    pub keycode: u8,
39    pub pressed: bool,
40    pub modifiers: u8,
41}
42
43#[derive(Clone, Copy, Debug)]
44pub struct MouseEvent {
45    pub dx: i8,
46    pub dy: i8,
47    pub dz: i8,
48    pub buttons: u8,
49}
50
51// USB to PS/2 scan code translation table (subset)
52// Maps USB HID usage IDs to PS/2 scan codes
53const USB_TO_PS2: [u8; 128] = [
54    0x00, 0x00, 0x00, 0x00, 0x1C, 0x32, 0x21, 0x23, // 00-07
55    0x1D, 0x24, 0x2B, 0x34, 0x33, 0x43, 0x35, 0x0E, // 08-0F
56    0x15, 0x16, 0x17, 0x1C, 0x18, 0x19, 0x14, 0x1A, // 10-17
57    0x1B, 0x1D, 0x1E, 0x21, 0x22, 0x23, 0x24, 0x2B, // 18-1F
58    0x29, 0x2F, 0x2E, 0x30, 0x20, 0x31, 0x32, 0x33, // 20-27
59    0x2C, 0x2D, 0x11, 0x12, 0x13, 0x3F, 0x3E, 0x46, // 28-2F
60    0x45, 0x5D, 0x4C, 0x36, 0x4A, 0x55, 0x37, 0x4E, // 30-37
61    0x57, 0x5E, 0x5C, 0x41, 0x52, 0x4D, 0x4B, 0x5B, // 38-3F
62    0x5A, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 40-47
63    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 48-4F
64    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 50-57
65    0x80, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58-5F
66    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 60-67
67    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 68-6F
68    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 70-77
69    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 78-7F
70];
71
72/// Performs the usb to ps2 operation.
73fn usb_to_ps2(keycode: u8) -> u8 {
74    if keycode < USB_TO_PS2.len() as u8 {
75        USB_TO_PS2[keycode as usize]
76    } else {
77        0x00
78    }
79}
80
81pub struct HidKeyboard {
82    controller: Arc<XhciController>,
83    port: usize,
84    interface: u8,
85    endpoint: u8,
86    max_packet: u16,
87    interval: u8,
88    event_queue: Vec<KeyEvent>,
89    last_report: [u8; KBD_REPORT_SIZE],
90}
91
92unsafe impl Send for HidKeyboard {}
93unsafe impl Sync for HidKeyboard {}
94
95impl HidKeyboard {
96    /// Creates a new instance.
97    pub fn new(
98        controller: Arc<XhciController>,
99        port: usize,
100        interface: u8,
101        endpoint: u8,
102        max_packet: u16,
103        interval: u8,
104    ) -> Self {
105        Self {
106            controller,
107            port,
108            interface,
109            endpoint,
110            max_packet,
111            interval,
112            event_queue: Vec::new(),
113            last_report: [0; KBD_REPORT_SIZE],
114        }
115    }
116
117    /// Reads event.
118    pub fn read_event(&mut self) -> Option<KeyEvent> {
119        if self.event_queue.is_empty() {
120            self.poll();
121        }
122        self.event_queue.pop()
123    }
124
125    /// Performs the poll operation.
126    pub fn poll(&mut self) {
127        // In a full implementation, this would submit an interrupt transfer
128        // and parse the HID report. For now, we simulate basic functionality.
129        // The actual polling would be done via xHCI interrupt transfers.
130    }
131
132    /// Performs the process report operation.
133    pub fn process_report(&mut self, report: &[u8; KBD_REPORT_SIZE]) {
134        // report[0] = modifiers
135        // report[1] = reserved
136        // report[2..7] = keycodes
137
138        let modifiers = report[0];
139
140        for i in 2..8 {
141            let keycode = report[i];
142            if keycode == 0 {
143                continue;
144            }
145
146            // Check if key was pressed (new in this report)
147            let was_pressed = self.last_report[2..8].contains(&keycode);
148            if !was_pressed {
149                self.event_queue.push(KeyEvent {
150                    keycode: usb_to_ps2(keycode),
151                    pressed: true,
152                    modifiers,
153                });
154            }
155        }
156
157        // Check for released keys
158        for i in 2..8 {
159            let keycode = self.last_report[i];
160            if keycode != 0 && !report[2..8].contains(&keycode) {
161                self.event_queue.push(KeyEvent {
162                    keycode: usb_to_ps2(keycode),
163                    pressed: false,
164                    modifiers,
165                });
166            }
167        }
168
169        self.last_report = *report;
170    }
171
172    /// Returns whether modifier pressed.
173    pub fn is_modifier_pressed(&self, modifier: u8) -> bool {
174        self.last_report[0] & modifier != 0
175    }
176}
177
178pub struct HidMouse {
179    controller: Arc<XhciController>,
180    port: usize,
181    interface: u8,
182    endpoint: u8,
183    max_packet: u16,
184    interval: u8,
185    event_queue: Vec<MouseEvent>,
186    last_buttons: u8,
187}
188
189unsafe impl Send for HidMouse {}
190unsafe impl Sync for HidMouse {}
191
192impl HidMouse {
193    /// Creates a new instance.
194    pub fn new(
195        controller: Arc<XhciController>,
196        port: usize,
197        interface: u8,
198        endpoint: u8,
199        max_packet: u16,
200        interval: u8,
201    ) -> Self {
202        Self {
203            controller,
204            port,
205            interface,
206            endpoint,
207            max_packet,
208            interval,
209            event_queue: Vec::new(),
210            last_buttons: 0,
211        }
212    }
213
214    /// Reads event.
215    pub fn read_event(&mut self) -> Option<MouseEvent> {
216        if self.event_queue.is_empty() {
217            self.poll();
218        }
219        self.event_queue.pop()
220    }
221
222    /// Performs the poll operation.
223    pub fn poll(&mut self) {
224        // In a full implementation, this would submit an interrupt transfer
225        // and parse the HID report.
226    }
227
228    /// Performs the process report operation.
229    pub fn process_report(&mut self, report: &[u8]) {
230        if report.len() < 3 {
231            return;
232        }
233
234        let buttons = report[0];
235        let dx = report[1] as i8;
236        let dy = report[2] as i8;
237        let dz = if report.len() > 3 { report[3] as i8 } else { 0 };
238
239        // Check for button changes
240        for i in 0..5 {
241            let mask = 1 << i;
242            let was_pressed = self.last_buttons & mask != 0;
243            let is_pressed = buttons & mask != 0;
244
245            if was_pressed != is_pressed {
246                self.event_queue.push(MouseEvent {
247                    dx: 0,
248                    dy: 0,
249                    dz: 0,
250                    buttons: if is_pressed { mask } else { 0 },
251                });
252            }
253        }
254
255        // Add movement event if there was movement
256        if dx != 0 || dy != 0 || dz != 0 {
257            self.event_queue.push(MouseEvent {
258                dx,
259                dy,
260                dz,
261                buttons,
262            });
263        }
264
265        self.last_buttons = buttons;
266    }
267
268    /// Returns whether button pressed.
269    pub fn is_button_pressed(&self, button: u8) -> bool {
270        self.last_buttons & (1 << button) != 0
271    }
272}
273
274static KEYBOARDS: Mutex<Vec<Arc<Mutex<HidKeyboard>>>> = Mutex::new(Vec::new());
275static MICE: Mutex<Vec<Arc<Mutex<HidMouse>>>> = Mutex::new(Vec::new());
276static HID_INITIALIZED: AtomicBool = AtomicBool::new(false);
277
278/// Performs the init operation.
279pub fn init() {
280    log::info!("[USB-HID] Initializing HID drivers...");
281
282    if !crate::hardware::usb::xhci::is_available() {
283        log::warn!("[USB-HID] xHCI not available, skipping HID init");
284        return;
285    }
286
287    if let Some(controller) = crate::hardware::usb::xhci::get_controller(0) {
288        for port in 0..controller.port_count() {
289            if controller.is_port_connected(port) {
290                log::info!("[USB-HID] Port {} connected, probing for HID...", port);
291                probe_hid_device(controller.clone(), port);
292            }
293        }
294    }
295
296    HID_INITIALIZED.store(true, Ordering::SeqCst);
297    log::info!(
298        "[USB-HID] Initialized: {} keyboard(s), {} mouse/mice",
299        KEYBOARDS.lock().len(),
300        MICE.lock().len()
301    );
302}
303
304/// Performs the probe hid device operation.
305fn probe_hid_device(controller: Arc<XhciController>, port: usize) {
306    // In a full implementation, this would:
307    // 1. Get device descriptor
308    // 2. Get configuration descriptor
309    // 3. Parse HID descriptors
310    // 4. Set configuration
311    // 5. Set boot protocol
312    // 6. Set up interrupt endpoints
313
314    // For now, we create placeholder devices
315    if port == 0 {
316        let keyboard = HidKeyboard::new(controller, port, 0, 0x81, 8, 10);
317        KEYBOARDS.lock().push(Arc::new(Mutex::new(keyboard)));
318        log::info!("[USB-HID] Found keyboard on port {}", port);
319    } else if port == 1 {
320        let mouse = HidMouse::new(controller, port, 0, 0x81, 4, 10);
321        MICE.lock().push(Arc::new(Mutex::new(mouse)));
322        log::info!("[USB-HID] Found mouse on port {}", port);
323    }
324}
325
326/// Returns keyboard.
327pub fn get_keyboard(index: usize) -> Option<Arc<Mutex<HidKeyboard>>> {
328    KEYBOARDS.lock().get(index).cloned()
329}
330
331/// Returns mouse.
332pub fn get_mouse(index: usize) -> Option<Arc<Mutex<HidMouse>>> {
333    MICE.lock().get(index).cloned()
334}
335
336/// Performs the keyboard count operation.
337pub fn keyboard_count() -> usize {
338    KEYBOARDS.lock().len()
339}
340
341/// Performs the mouse count operation.
342pub fn mouse_count() -> usize {
343    MICE.lock().len()
344}
345
346/// Returns whether available.
347pub fn is_available() -> bool {
348    HID_INITIALIZED.load(Ordering::Relaxed)
349}