1#![allow(dead_code)]
9
10use crate::error::KernelError;
11
12pub const HID_DESCRIPTOR_TYPE: u8 = 0x21;
18pub const HID_REPORT_DESCRIPTOR_TYPE: u8 = 0x22;
20pub const HID_PHYSICAL_DESCRIPTOR_TYPE: u8 = 0x23;
22
23pub const HID_GET_REPORT: u8 = 0x01;
26pub const HID_GET_IDLE: u8 = 0x02;
28pub const HID_GET_PROTOCOL: u8 = 0x03;
30pub const HID_SET_REPORT: u8 = 0x09;
32pub const HID_SET_IDLE: u8 = 0x0A;
34pub const HID_SET_PROTOCOL: u8 = 0x0B;
36
37pub const HID_PROTOCOL_BOOT: u8 = 0;
40pub const HID_PROTOCOL_REPORT: u8 = 1;
42
43pub const HID_SUBCLASS_NONE: u8 = 0x00;
46pub const HID_SUBCLASS_BOOT: u8 = 0x01;
48
49pub const HID_BOOT_PROTOCOL_KEYBOARD: u8 = 0x01;
52pub const HID_BOOT_PROTOCOL_MOUSE: u8 = 0x02;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[repr(u8)]
62pub enum HidItemType {
63 Main = 0,
65 Global = 1,
67 Local = 2,
69 Reserved = 3,
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75#[repr(u8)]
76pub enum HidMainTag {
77 Input = 0x08,
78 Output = 0x09,
79 Feature = 0x0B,
80 Collection = 0x0A,
81 EndCollection = 0x0C,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86#[repr(u8)]
87pub enum HidGlobalTag {
88 UsagePage = 0x00,
89 LogicalMinimum = 0x01,
90 LogicalMaximum = 0x02,
91 PhysicalMinimum = 0x03,
92 PhysicalMaximum = 0x04,
93 UnitExponent = 0x05,
94 Unit = 0x06,
95 ReportSize = 0x07,
96 ReportId = 0x08,
97 ReportCount = 0x09,
98 Push = 0x0A,
99 Pop = 0x0B,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104#[repr(u16)]
105pub enum HidUsagePage {
106 GenericDesktop = 0x01,
107 SimulationControls = 0x02,
108 VrControls = 0x03,
109 SportControls = 0x04,
110 GameControls = 0x05,
111 GenericDevice = 0x06,
112 Keyboard = 0x07,
113 Led = 0x08,
114 Button = 0x09,
115 Consumer = 0x0C,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120#[repr(u16)]
121pub enum HidDesktopUsage {
122 Pointer = 0x01,
123 Mouse = 0x02,
124 Joystick = 0x04,
125 Gamepad = 0x05,
126 Keyboard = 0x06,
127 Keypad = 0x07,
128 X = 0x30,
129 Y = 0x31,
130 Z = 0x32,
131 Wheel = 0x38,
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum HidDeviceType {
141 Keyboard,
143 Mouse,
145 Gamepad,
147 Generic,
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum InputEvent {
158 KeyPress(u8),
160 KeyRelease(u8),
162 MouseMove(i16, i16),
164 MouseButton(u8, bool),
166 MouseScroll(i8),
168}
169
170#[derive(Debug, Clone, Copy)]
182#[repr(C, packed)]
183pub struct BootKeyboardReport {
184 pub modifiers: u8,
185 pub reserved: u8,
186 pub keys: [u8; 6],
187}
188
189impl BootKeyboardReport {
190 pub const fn empty() -> Self {
192 Self {
193 modifiers: 0,
194 reserved: 0,
195 keys: [0; 6],
196 }
197 }
198
199 pub fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
201 if data.len() < 8 {
202 return Err(KernelError::InvalidArgument {
203 name: "hid_report",
204 value: "keyboard report must be 8 bytes",
205 });
206 }
207 Ok(Self {
208 modifiers: data[0],
209 reserved: data[1],
210 keys: [data[2], data[3], data[4], data[5], data[6], data[7]],
211 })
212 }
213
214 pub fn has_modifier(&self, bit: u8) -> bool {
216 (self.modifiers & (1 << bit)) != 0
217 }
218
219 pub fn left_ctrl(&self) -> bool {
221 self.has_modifier(0)
222 }
223 pub fn left_shift(&self) -> bool {
225 self.has_modifier(1)
226 }
227 pub fn left_alt(&self) -> bool {
229 self.has_modifier(2)
230 }
231 pub fn left_gui(&self) -> bool {
233 self.has_modifier(3)
234 }
235}
236
237#[derive(Debug, Clone, Copy)]
244#[repr(C, packed)]
245pub struct BootMouseReport {
246 pub buttons: u8,
247 pub x_displacement: i8,
248 pub y_displacement: i8,
249 pub scroll: i8,
250}
251
252impl BootMouseReport {
253 pub const fn empty() -> Self {
255 Self {
256 buttons: 0,
257 x_displacement: 0,
258 y_displacement: 0,
259 scroll: 0,
260 }
261 }
262
263 pub fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
265 if data.len() < 3 {
266 return Err(KernelError::InvalidArgument {
267 name: "hid_report",
268 value: "mouse report must be at least 3 bytes",
269 });
270 }
271 Ok(Self {
272 buttons: data[0],
273 x_displacement: data[1] as i8,
274 y_displacement: data[2] as i8,
275 scroll: if data.len() >= 4 { data[3] as i8 } else { 0 },
276 })
277 }
278
279 pub fn left_button(&self) -> bool {
281 (self.buttons & 0x01) != 0
282 }
283 pub fn right_button(&self) -> bool {
285 (self.buttons & 0x02) != 0
286 }
287 pub fn middle_button(&self) -> bool {
289 (self.buttons & 0x04) != 0
290 }
291}
292
293#[derive(Debug, Clone)]
299pub struct HidCapabilities {
300 pub device_type: HidDeviceType,
302 pub report_id_count: u8,
304 pub boot_protocol: bool,
306 pub max_input_report_size: u16,
308 pub max_output_report_size: u16,
310}
311
312impl HidCapabilities {
313 pub fn boot_keyboard() -> Self {
315 Self {
316 device_type: HidDeviceType::Keyboard,
317 report_id_count: 0,
318 boot_protocol: true,
319 max_input_report_size: 8,
320 max_output_report_size: 1, }
322 }
323
324 pub fn boot_mouse() -> Self {
326 Self {
327 device_type: HidDeviceType::Mouse,
328 report_id_count: 0,
329 boot_protocol: true,
330 max_input_report_size: 4,
331 max_output_report_size: 0,
332 }
333 }
334}
335
336pub fn parse_report_descriptor(descriptor: &[u8]) -> Result<HidCapabilities, KernelError> {
343 if descriptor.is_empty() {
344 return Err(KernelError::InvalidArgument {
345 name: "descriptor",
346 value: "empty report descriptor",
347 });
348 }
349
350 let mut device_type = HidDeviceType::Generic;
351 let mut usage_page: u16 = 0;
352 let mut report_id_count: u8 = 0;
353 let mut i = 0;
354
355 while i < descriptor.len() {
356 let prefix = descriptor[i];
357
358 if prefix == 0xFE {
360 if i + 2 < descriptor.len() {
361 let data_size = descriptor[i + 1] as usize;
362 i += 3 + data_size;
363 } else {
364 break;
365 }
366 continue;
367 }
368
369 let size = match prefix & 0x03 {
371 0 => 0usize,
372 1 => 1,
373 2 => 2,
374 3 => 4, _ => unreachable!(),
376 };
377 let item_type = (prefix >> 2) & 0x03;
378 let tag = (prefix >> 4) & 0x0F;
379
380 let data = if size > 0 && i + size < descriptor.len() {
382 let mut val: u32 = 0;
383 for j in 0..size {
384 val |= (descriptor[i + 1 + j] as u32) << (j * 8);
385 }
386 val
387 } else {
388 0
389 };
390
391 match item_type {
392 1 => {
394 match tag {
395 0x00 => {
396 usage_page = data as u16;
398 }
399 0x08 => {
400 report_id_count = report_id_count.saturating_add(1);
402 }
403 _ => {}
404 }
405 }
406 2 => {
408 if tag == 0x00 {
409 let usage = data as u16;
411 if usage_page == HidUsagePage::GenericDesktop as u16 {
413 match usage {
414 0x06 | 0x07 => device_type = HidDeviceType::Keyboard,
415 0x02 => device_type = HidDeviceType::Mouse,
416 0x04 | 0x05 => device_type = HidDeviceType::Gamepad,
417 _ => {}
418 }
419 }
420 }
421 }
422 _ => {}
423 }
424
425 i += 1 + size;
426 }
427
428 Ok(HidCapabilities {
429 device_type,
430 report_id_count,
431 boot_protocol: matches!(device_type, HidDeviceType::Keyboard | HidDeviceType::Mouse),
432 max_input_report_size: match device_type {
433 HidDeviceType::Keyboard => 8,
434 HidDeviceType::Mouse => 4,
435 _ => 64,
436 },
437 max_output_report_size: match device_type {
438 HidDeviceType::Keyboard => 1,
439 _ => 0,
440 },
441 })
442}
443
444const MAX_REPORT_SIZE: usize = 64;
450
451#[derive(Debug)]
453pub struct HidDevice {
454 pub address: u8,
456 pub interface: u8,
458 pub device_type: HidDeviceType,
460 pub interrupt_endpoint: u8,
462 pub poll_interval_ms: u8,
464 pub max_packet_size: u16,
466 pub boot_protocol: bool,
468 pub capabilities: HidCapabilities,
470 prev_keyboard_report: BootKeyboardReport,
472 prev_mouse_buttons: u8,
474 report_buffer: [u8; MAX_REPORT_SIZE],
476 report_len: usize,
478}
479
480impl HidDevice {
481 pub fn new_boot_keyboard(address: u8, interface: u8, endpoint: u8, interval: u8) -> Self {
483 Self {
484 address,
485 interface,
486 device_type: HidDeviceType::Keyboard,
487 interrupt_endpoint: endpoint,
488 poll_interval_ms: interval,
489 max_packet_size: 8,
490 boot_protocol: true,
491 capabilities: HidCapabilities::boot_keyboard(),
492 prev_keyboard_report: BootKeyboardReport::empty(),
493 prev_mouse_buttons: 0,
494 report_buffer: [0; MAX_REPORT_SIZE],
495 report_len: 0,
496 }
497 }
498
499 pub fn new_boot_mouse(address: u8, interface: u8, endpoint: u8, interval: u8) -> Self {
501 Self {
502 address,
503 interface,
504 device_type: HidDeviceType::Mouse,
505 interrupt_endpoint: endpoint,
506 poll_interval_ms: interval,
507 max_packet_size: 4,
508 boot_protocol: true,
509 capabilities: HidCapabilities::boot_mouse(),
510 prev_keyboard_report: BootKeyboardReport::empty(),
511 prev_mouse_buttons: 0,
512 report_buffer: [0; MAX_REPORT_SIZE],
513 report_len: 0,
514 }
515 }
516
517 pub fn from_capabilities(
519 address: u8,
520 interface: u8,
521 endpoint: u8,
522 interval: u8,
523 caps: HidCapabilities,
524 ) -> Self {
525 Self {
526 address,
527 interface,
528 device_type: caps.device_type,
529 interrupt_endpoint: endpoint,
530 poll_interval_ms: interval,
531 max_packet_size: caps.max_input_report_size,
532 boot_protocol: caps.boot_protocol,
533 capabilities: caps,
534 prev_keyboard_report: BootKeyboardReport::empty(),
535 prev_mouse_buttons: 0,
536 report_buffer: [0; MAX_REPORT_SIZE],
537 report_len: 0,
538 }
539 }
540
541 pub fn submit_report(&mut self, data: &[u8]) -> Result<(), KernelError> {
546 if data.is_empty() {
547 return Err(KernelError::InvalidArgument {
548 name: "report_data",
549 value: "empty report",
550 });
551 }
552 let len = data.len().min(MAX_REPORT_SIZE);
553 self.report_buffer[..len].copy_from_slice(&data[..len]);
554 self.report_len = len;
555 Ok(())
556 }
557
558 pub fn process_report(&mut self) -> Result<InputEventBatch, KernelError> {
564 if self.report_len == 0 {
565 return Ok(InputEventBatch::empty());
566 }
567
568 let mut local_buf = [0u8; MAX_REPORT_SIZE];
571 let len = self.report_len;
572 local_buf[..len].copy_from_slice(&self.report_buffer[..len]);
573
574 match self.device_type {
575 HidDeviceType::Keyboard => self.process_keyboard_report(&local_buf[..len]),
576 HidDeviceType::Mouse => self.process_mouse_report(&local_buf[..len]),
577 _ => Ok(InputEventBatch::empty()),
578 }
579 }
580
581 fn process_keyboard_report(&mut self, data: &[u8]) -> Result<InputEventBatch, KernelError> {
583 let report = BootKeyboardReport::from_bytes(data)?;
584 let mut batch = InputEventBatch::empty();
585
586 let mod_diff = report.modifiers ^ self.prev_keyboard_report.modifiers;
588 for bit in 0..8u8 {
589 if mod_diff & (1 << bit) != 0 {
590 let keycode = 0xE0 + bit;
592 if report.modifiers & (1 << bit) != 0 {
593 batch.push(InputEvent::KeyPress(keycode));
594 } else {
595 batch.push(InputEvent::KeyRelease(keycode));
596 }
597 }
598 }
599
600 for &key in &report.keys {
602 if key == 0 {
603 continue;
604 }
605 let was_pressed = self.prev_keyboard_report.keys.contains(&key);
606 if !was_pressed {
607 batch.push(InputEvent::KeyPress(key));
608 }
609 }
610
611 for &key in &self.prev_keyboard_report.keys {
613 if key == 0 {
614 continue;
615 }
616 let still_pressed = report.keys.contains(&key);
617 if !still_pressed {
618 batch.push(InputEvent::KeyRelease(key));
619 }
620 }
621
622 self.prev_keyboard_report = report;
623 Ok(batch)
624 }
625
626 fn process_mouse_report(&mut self, data: &[u8]) -> Result<InputEventBatch, KernelError> {
628 let report = BootMouseReport::from_bytes(data)?;
629 let mut batch = InputEventBatch::empty();
630
631 if report.x_displacement != 0 || report.y_displacement != 0 {
633 batch.push(InputEvent::MouseMove(
634 report.x_displacement as i16,
635 report.y_displacement as i16,
636 ));
637 }
638
639 let btn_diff = report.buttons ^ self.prev_mouse_buttons;
641 for bit in 0..3u8 {
642 if btn_diff & (1 << bit) != 0 {
643 let pressed = report.buttons & (1 << bit) != 0;
644 batch.push(InputEvent::MouseButton(bit, pressed));
645 }
646 }
647
648 if report.scroll != 0 {
650 batch.push(InputEvent::MouseScroll(report.scroll));
651 }
652
653 self.prev_mouse_buttons = report.buttons;
654 Ok(batch)
655 }
656
657 #[cfg(target_os = "none")]
664 pub fn poll_device(&mut self) -> Option<InputEvent> {
665 None
674 }
675
676 #[cfg(not(target_os = "none"))]
678 pub fn poll_device(&mut self) -> Option<InputEvent> {
679 None
680 }
681}
682
683const MAX_EVENTS_PER_REPORT: usize = 16;
689
690#[derive(Debug, Clone)]
692pub struct InputEventBatch {
693 events: [Option<InputEvent>; MAX_EVENTS_PER_REPORT],
694 count: usize,
695}
696
697impl InputEventBatch {
698 pub const fn empty() -> Self {
700 Self {
701 events: [None; MAX_EVENTS_PER_REPORT],
702 count: 0,
703 }
704 }
705
706 pub fn push(&mut self, event: InputEvent) {
708 if self.count < MAX_EVENTS_PER_REPORT {
709 self.events[self.count] = Some(event);
710 self.count += 1;
711 }
712 }
713
714 pub fn len(&self) -> usize {
716 self.count
717 }
718
719 pub fn is_empty(&self) -> bool {
721 self.count == 0
722 }
723
724 pub fn first(&self) -> Option<InputEvent> {
726 if self.count > 0 {
727 self.events[0]
728 } else {
729 None
730 }
731 }
732
733 pub fn iter(&self) -> InputEventBatchIter<'_> {
735 InputEventBatchIter {
736 batch: self,
737 index: 0,
738 }
739 }
740}
741
742pub struct InputEventBatchIter<'a> {
744 batch: &'a InputEventBatch,
745 index: usize,
746}
747
748impl<'a> Iterator for InputEventBatchIter<'a> {
749 type Item = InputEvent;
750
751 fn next(&mut self) -> Option<Self::Item> {
752 if self.index < self.batch.count {
753 let event = self.batch.events[self.index];
754 self.index += 1;
755 event
756 } else {
757 None
758 }
759 }
760}
761
762#[cfg(test)]
767mod tests {
768 use super::*;
769
770 #[test]
771 fn test_boot_keyboard_report_parse() {
772 let data = [0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00];
774 let report = BootKeyboardReport::from_bytes(&data).unwrap();
775 assert_eq!(report.modifiers, 0x02);
776 assert!(report.left_shift());
777 assert!(!report.left_ctrl());
778 assert_eq!(report.keys[0], 0x04);
779 assert_eq!(report.keys[1], 0x00);
780 }
781
782 #[test]
783 fn test_boot_keyboard_report_too_short() {
784 let data = [0x02, 0x00, 0x04];
785 let result = BootKeyboardReport::from_bytes(&data);
786 assert!(result.is_err());
787 }
788
789 #[test]
790 fn test_boot_mouse_report_parse() {
791 let data: [u8; 3] = [0x01, 10, (-5i8) as u8];
793 let report = BootMouseReport::from_bytes(&data).unwrap();
794 assert!(report.left_button());
795 assert!(!report.right_button());
796 assert_eq!(report.x_displacement, 10);
797 assert_eq!(report.y_displacement, -5);
798 assert_eq!(report.scroll, 0); }
800
801 #[test]
802 fn test_boot_mouse_report_with_scroll() {
803 let data: [u8; 4] = [0x04, 0, 0, (-3i8) as u8]; let report = BootMouseReport::from_bytes(&data).unwrap();
805 assert!(report.middle_button());
806 assert!(!report.left_button());
807 assert_eq!(report.scroll, -3);
808 }
809
810 #[test]
811 fn test_keyboard_event_generation() {
812 let mut dev = HidDevice::new_boot_keyboard(1, 0, 0x81, 10);
813
814 let data = [0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00];
816 dev.submit_report(&data).unwrap();
817 let batch = dev.process_report().unwrap();
818 assert_eq!(batch.len(), 1);
819 assert_eq!(batch.first(), Some(InputEvent::KeyPress(0x04)));
820
821 let data = [0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00];
823 dev.submit_report(&data).unwrap();
824 let batch = dev.process_report().unwrap();
825 assert_eq!(batch.len(), 2);
827 let events: [Option<InputEvent>; 2] = [
828 batch
829 .iter()
830 .find(|e| matches!(e, InputEvent::KeyPress(0x05))),
831 batch
832 .iter()
833 .find(|e| matches!(e, InputEvent::KeyRelease(0x04))),
834 ];
835 assert!(events[0].is_some());
836 assert!(events[1].is_some());
837 }
838
839 #[test]
840 fn test_mouse_event_generation() {
841 let mut dev = HidDevice::new_boot_mouse(2, 0, 0x81, 10);
842
843 let data: [u8; 4] = [0x01, 20, (-10i8) as u8, 0];
845 dev.submit_report(&data).unwrap();
846 let batch = dev.process_report().unwrap();
847
848 assert!(batch.len() >= 2);
850 let has_move = batch
851 .iter()
852 .any(|e| matches!(e, InputEvent::MouseMove(20, -10)));
853 let has_btn = batch
854 .iter()
855 .any(|e| matches!(e, InputEvent::MouseButton(0, true)));
856 assert!(has_move);
857 assert!(has_btn);
858 }
859
860 #[test]
861 fn test_report_descriptor_keyboard_detection() {
862 let descriptor: [u8; 4] = [
864 0x05, 0x01, 0x09, 0x06, ];
867 let caps = parse_report_descriptor(&descriptor).unwrap();
868 assert_eq!(caps.device_type, HidDeviceType::Keyboard);
869 assert!(caps.boot_protocol);
870 assert_eq!(caps.max_input_report_size, 8);
871 }
872
873 #[test]
874 fn test_report_descriptor_mouse_detection() {
875 let descriptor: [u8; 4] = [
877 0x05, 0x01, 0x09, 0x02, ];
880 let caps = parse_report_descriptor(&descriptor).unwrap();
881 assert_eq!(caps.device_type, HidDeviceType::Mouse);
882 assert!(caps.boot_protocol);
883 assert_eq!(caps.max_input_report_size, 4);
884 }
885
886 #[test]
887 fn test_report_descriptor_empty() {
888 let result = parse_report_descriptor(&[]);
889 assert!(result.is_err());
890 }
891
892 #[test]
893 fn test_input_event_batch_overflow() {
894 let mut batch = InputEventBatch::empty();
895 for i in 0..MAX_EVENTS_PER_REPORT + 5 {
896 batch.push(InputEvent::KeyPress(i as u8));
897 }
898 assert_eq!(batch.len(), MAX_EVENTS_PER_REPORT);
900 }
901
902 #[test]
903 fn test_poll_device_returns_none() {
904 let mut dev = HidDevice::new_boot_keyboard(1, 0, 0x81, 10);
905 assert_eq!(dev.poll_device(), None);
906 }
907}