11/* usb_hid.c */
22#include "usb_hid.h"
33
4- static void hid_keyboard_report_cb (struct usb_dev * ud , const uint8_t * pkt , uint16_t len ) {
5- if (len < 8u ) {
6- return ;
4+ static uint8_t last_report [8 ];
5+
6+ /* sink for raw scancodes (make = code, break = code|0x80) */
7+ void keyboard_process_scancode_input (uint8_t sc );
8+
9+ /* last 8-byte HID boot report snapshot */
10+ static uint8_t last_report [8 ];
11+
12+ static inline void emit_make (uint8_t code ) {
13+ if (code ) {
14+ keyboard_process_scancode_input (code );
15+ }
16+ }
17+ static inline void emit_break (uint8_t code ) {
18+ if (code ) {
19+ keyboard_process_scancode_input ((uint8_t )(code | 0x80u ));
20+ }
21+ }
22+
23+ /* USB HID Boot Keyboard usage -> PS/2 Set-1 MAKE code (no break bit).
24+ * 0 means "unmapped/ignore".
25+ */
26+ static const uint8_t hid_to_set1 [0xE8 ] = {
27+ /* Letters a..z (0x04..0x1D) */
28+ [0x04 ]= 0x1E , /* A */ [0x05 ]= 0x30 , /* B */ [0x06 ]= 0x2E , /* C */ [0x07 ]= 0x20 , /* D */
29+ [0x08 ]= 0x12 , /* E */ [0x09 ]= 0x21 , /* F */ [0x0A ]= 0x22 , /* G */ [0x0B ]= 0x23 , /* H */
30+ [0x0C ]= 0x17 , /* I */ [0x0D ]= 0x24 , /* J */ [0x0E ]= 0x25 , /* K */ [0x0F ]= 0x26 , /* L */
31+ [0x10 ]= 0x32 , /* M */ [0x11 ]= 0x31 , /* N */ [0x12 ]= 0x18 , /* O */ [0x13 ]= 0x19 , /* P */
32+ [0x14 ]= 0x10 , /* Q */ [0x15 ]= 0x13 , /* R */ [0x16 ]= 0x1F , /* S */ [0x17 ]= 0x14 , /* T */
33+ [0x18 ]= 0x16 , /* U */ [0x19 ]= 0x2F , /* V */ [0x1A ]= 0x11 , /* W */ [0x1B ]= 0x2D , /* X */
34+ [0x1C ]= 0x15 , /* Y */ [0x1D ]= 0x2C , /* Z */
35+
36+ /* Number row 1..0 (0x1E..0x27) */
37+ [0x1E ]= 0x02 ,[0x1F ]= 0x03 ,[0x20 ]= 0x04 ,[0x21 ]= 0x05 ,[0x22 ]= 0x06 ,
38+ [0x23 ]= 0x07 ,[0x24 ]= 0x08 ,[0x25 ]= 0x09 ,[0x26 ]= 0x0A ,[0x27 ]= 0x0B ,
39+
40+ /* Control / punctuation (0x28..0x38) */
41+ [0x28 ]= 0x1C , /* Enter */
42+ [0x29 ]= 0x01 , /* Escape */
43+ [0x2A ]= 0x0E , /* Backspace */
44+ [0x2B ]= 0x0F , /* Tab */
45+ [0x2C ]= 0x39 , /* Space */
46+ [0x2D ]= 0x0C , /* - */
47+ [0x2E ]= 0x0D , /* = */
48+ [0x2F ]= 0x1A , /* [ */
49+ [0x30 ]= 0x1B , /* ] */
50+ [0x31 ]= 0x2B , /* \ (US) */
51+ /* 0x32 = Non-US #/~ (ISO “102nd key”): Set-1 = 0x56 on ISO keyboards */
52+ [0x32 ]= 0x56 ,
53+ [0x33 ]= 0x27 , /* ; */
54+ [0x34 ]= 0x28 , /* ' */
55+ [0x35 ]= 0x29 , /* ` */
56+ [0x36 ]= 0x33 , /* , */
57+ [0x37 ]= 0x34 , /* . */
58+ [0x38 ]= 0x35 , /* / */
59+
60+ /* Locks & F-keys */
61+ [0x39 ]= 0x3A , /* Caps Lock */
62+ [0x3A ]= 0x3B , /* F1 */ [0x3B ]= 0x3C , /* F2 */ [0x3C ]= 0x3D , /* F3 */
63+ [0x3D ]= 0x3E , /* F4 */ [0x3E ]= 0x3F , /* F5 */ [0x3F ]= 0x40 , /* F6 */
64+ [0x40 ]= 0x41 , /* F7 */ [0x41 ]= 0x42 , /* F8 */ [0x42 ]= 0x43 , /* F9 */
65+ [0x43 ]= 0x44 , /* F10 */ [0x44 ]= 0x57 , /* F11 */ [0x45 ]= 0x58 , /* F12 */
66+
67+ /* Print/Scroll/Pause */
68+ /* [0x46] PrintScreen -> E0 2A E0 37 (complex), leave 0 for now */
69+ [0x47 ]= 0x46 , /* Scroll Lock */
70+ /* [0x48] Pause -> complex, leave unmapped here */
71+
72+ /* Insert/Home/PgUp/Delete/End/PgDn & arrows (all extended: prefix 0xE0) */
73+ [0x49 ]= 0x52 , /* Insert -> E0 52 */
74+ [0x4A ]= 0x47 , /* Home -> E0 47 */
75+ [0x4B ]= 0x49 , /* PageUp -> E0 49 */
76+ [0x4C ]= 0x53 , /* Delete -> E0 53 */
77+ [0x4D ]= 0x4F , /* End -> E0 4F */
78+ [0x4E ]= 0x51 , /* PageDn -> E0 51 */
79+ [0x4F ]= 0x4D , /* Right -> E0 4D */
80+ [0x50 ]= 0x4B , /* Left -> E0 4B */
81+ [0x51 ]= 0x50 , /* Down -> E0 50 */
82+ [0x52 ]= 0x48 , /* Up -> E0 48 */
83+
84+ /* Keypad cluster */
85+ [0x53 ]= 0x45 , /* Num Lock */
86+ [0x54 ]= 0x35 , /* KP / -> E0 35 (extended) */
87+ [0x55 ]= 0x37 , /* KP * */
88+ [0x56 ]= 0x4A , /* KP - */
89+ [0x57 ]= 0x4E , /* KP + */
90+ [0x58 ]= 0x1C , /* KP Enter -> E0 1C (extended) */
91+ [0x59 ]= 0x4F , /* KP 1 */ [0x5A ]= 0x50 , /* KP 2 */ [0x5B ]= 0x51 , /* KP 3 */
92+ [0x5C ]= 0x4B , /* KP 4 */ [0x5D ]= 0x4C , /* KP 5 */ [0x5E ]= 0x4D , /* KP 6 */
93+ [0x5F ]= 0x47 , /* KP 7 */ [0x60 ]= 0x48 , /* KP 8 */ [0x61 ]= 0x49 , /* KP 9 */
94+ [0x62 ]= 0x52 , /* KP 0 */ [0x63 ]= 0x53 , /* KP . */
95+
96+ /* Application/Menu (extended) & Non-US \| on ISO boards */
97+ [0x65 ]= 0x5D , /* Application -> E0 5D */
98+
99+ /* Modifiers (L* are normal, R* are extended in Set-1) */
100+ [0xE0 ]= 0x1D , /* LCtrl */
101+ [0xE1 ]= 0x2A , /* LShift */
102+ [0xE2 ]= 0x38 , /* LAlt */
103+ [0xE3 ]= 0x5B , /* LGUI (Win) -> E0 5B */
104+ [0xE4 ]= 0x1D , /* RCtrl -> E0 1D */
105+ [0xE5 ]= 0x36 , /* RShift */
106+ [0xE6 ]= 0x38 , /* RAlt (AltGr) -> E0 38 */
107+ [0xE7 ]= 0x5C , /* RGUI -> E0 5C */
108+ };
109+
110+ /* Which HID usages should be emitted with an 0xE0 prefix in Set-1? */
111+ static inline int hid_usage_needs_e0 (uint8_t u )
112+ {
113+ switch (u ) {
114+ /* arrows + edit cluster */
115+ case 0x49 : case 0x4A : case 0x4B : case 0x4C :
116+ case 0x4D : case 0x4E : case 0x4F : case 0x50 :
117+ case 0x51 : case 0x52 :
118+ /* keypad / and Enter */
119+ case 0x54 : case 0x58 :
120+ /* right-side modifiers and GUI keys */
121+ case 0xE4 : case 0xE6 : case 0xE3 : case 0xE7 :
122+ return 1 ;
123+ default :
124+ return 0 ;
7125 }
8- dprintf ("keyboard report cb\n" );
9- /* pkt[2..7] are keycodes; translate via simple table, raise input events */
10- /* Minimal: stash last key, push to your input layer. */
11126}
12127
13- /* Call this right after you arm EP1-IN (before “waiting for interrupts”). */
14- static void hid_try_get_report_snapshot (struct usb_dev * ud ) {
15- uint8_t __attribute__((aligned (64 ))) setup [8 ] = {
16- 0xA1 , 0x01 , /* bmReqType=Class|Interface|IN, bRequest=GET_REPORT */
17- 0x01 , 0x00 , /* wValue = (ReportType=Input=1)<<8 | ReportID=0 */
18- 0x00 , 0x00 , /* wIndex = interface 0 */
19- 0x08 , 0x00 /* wLength = 8 */
20- };
21- uint8_t __attribute__((aligned (64 ))) buf [8 ] = {0 };
22- int ok = xhci_ctrl_xfer (ud , setup , buf , 8 , 1 );
23- dprintf ("hid: GET_REPORT(Input,id=0) %s, data=%02x %02x %02x %02x %02x %02x %02x %02x\n" ,
24- ok ? "OK" : "FAIL" ,
25- buf [0 ],buf [1 ],buf [2 ],buf [3 ],buf [4 ],buf [5 ],buf [6 ],buf [7 ]);
128+ static inline uint8_t hid_usage_to_set1 (uint8_t u )
129+ {
130+ return (u < sizeof (hid_to_set1 )) ? hid_to_set1 [u ] : 0 ;
131+ }
132+
133+ static int usage_present (const uint8_t * rep , uint8_t usage )
134+ {
135+ for (int i = 2 ; i < 8 ; ++ i ) if (rep [i ] == usage ) return 1 ;
136+ return 0 ;
137+ }
138+
139+ static void process_mod_changes (uint8_t prev_mod , uint8_t cur_mod )
140+ {
141+ uint8_t changed = (uint8_t )(prev_mod ^ cur_mod );
142+ while (changed ) {
143+ uint8_t bit = (uint8_t )(changed & (uint8_t )(- ((int8_t )changed )));
144+ int idx = __builtin_ctz (changed ); /* 0..7 */
145+ uint8_t usage = (uint8_t )(0xE0u + idx );
146+ uint8_t make = hid_usage_to_set1 (usage );
147+ if (cur_mod & bit ) emit_make (make ); else emit_break (make );
148+ changed = (uint8_t )(changed & (changed - 1 ));
149+ }
26150}
27151
28- static void hid_toggle_numlock (struct usb_dev * ud , int on ) {
29- uint8_t __attribute__((aligned (64 ))) setup [8 ] = {
30- 0x21 , 0x09 , /* bmReqType=Class|Interface|OUT, bRequest=SET_REPORT */
31- 0x02 , 0x00 , /* wValue = (ReportType=Output=2)<<8 | ReportID=0 */
32- 0x00 , 0x00 , /* wIndex = interface 0 */
33- 0x01 , 0x00 /* wLength = 1 */
34- };
35- uint8_t __attribute__((aligned (64 ))) led = (on ? 0x01 : 0x00 ); /* bit0 = NumLock */
36- int ok = xhci_ctrl_xfer (ud , setup , & led , 1 , 0 );
37- dprintf ("hid: SET_REPORT(Output LED NumLock=%d) %s\n" , on , ok ? "OK" : "FAIL" );
152+ static void hid_keyboard_report_cb (struct usb_dev * ud , const uint8_t * pkt , uint16_t len )
153+ {
154+ (void )ud ;
155+ if (len < 8u ) return ;
156+
157+ /* drop identical snapshot (disables HID’s built-in key repeat) */
158+ if (memcmp (pkt , last_report , 8 ) == 0 ) return ;
159+
160+ /* 1) modifiers (byte 0) */
161+ process_mod_changes (last_report [0 ], pkt [0 ]);
162+
163+ /* 2) key array (bytes 2..7): releases first… */
164+ for (int i = 2 ; i < 8 ; ++ i ) {
165+ uint8_t u = last_report [i ];
166+ if (u && !usage_present (pkt , u )) {
167+ uint8_t mk = hid_usage_to_set1 (u );
168+ emit_break (mk );
169+ }
170+ }
171+ /* …then presses */
172+ for (int i = 2 ; i < 8 ; ++ i ) {
173+ uint8_t u = pkt [i ];
174+ if (u && !usage_present (last_report , u )) {
175+ uint8_t mk = hid_usage_to_set1 (u );
176+ emit_make (mk );
177+ }
178+ }
179+
180+ memcpy (last_report , pkt , 8 );
38181}
39182
40183static void hid_on_device_added (const struct usb_dev * ud_c )
@@ -43,11 +186,8 @@ static void hid_on_device_added(const struct usb_dev *ud_c)
43186 if (!ud_c ) return ;
44187
45188 /* Only handle HID Boot Keyboard */
46- if (!(ud_c -> dev_class == USB_CLASS_HID &&
47- ud_c -> dev_subclass == USB_SUBCLASS_BOOT &&
48- ud_c -> dev_proto == USB_PROTO_KEYBOARD )) {
49- dprintf ("hid: ignore dev class=%02x sub=%02x proto=%02x\n" ,
50- ud_c -> dev_class , ud_c -> dev_subclass , ud_c -> dev_proto );
189+ if (!(ud_c -> dev_class == USB_CLASS_HID && ud_c -> dev_subclass == USB_SUBCLASS_BOOT && ud_c -> dev_proto == USB_PROTO_KEYBOARD )) {
190+ dprintf ("hid: ignore dev class=%02x sub=%02x proto=%02x\n" , ud_c -> dev_class , ud_c -> dev_subclass , ud_c -> dev_proto );
51191 return ;
52192 }
53193
@@ -102,9 +242,6 @@ static void hid_on_device_added(const struct usb_dev *ud_c)
102242 return ;
103243 }
104244 dprintf ("hid: keyboard armed (EP1 IN), waiting for interrupts\n" );
105-
106- hid_try_get_report_snapshot (ud );
107- hid_toggle_numlock (ud , 1 );
108245}
109246
110247static void hid_on_device_removed (const struct usb_dev * ud ) {
0 commit comments