Skip to content

Commit 0ee7a96

Browse files
now delivers keycodes. prone to random lockup
1 parent 635746e commit 0ee7a96

File tree

6 files changed

+388
-233
lines changed

6 files changed

+388
-233
lines changed

include/keyboard.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,13 @@ void load_keymap_from_string(const char* text);
134134
bool key_waiting();
135135

136136
_Noreturn void reboot(void);
137+
138+
/**
139+
* @brief Push a keyboard scan code into the keyboard buffer.
140+
*
141+
* This is a generic input function that can be fed by the
142+
* PS2 keyboard interrupt, XHCI HID, a spool file, or whatever.
143+
*
144+
* @param sc Scan code
145+
*/
146+
void keyboard_process_scancode_input(uint8_t sc);

include/usb_hid.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* usb_hid.h */
21
#pragma once
32
#include <kernel.h>
43
#include "usb_core.h"

include/usb_xhci.h

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct usb_ep {
7878

7979
/* bits in TRB dword3 */
8080
#define TRB_CYCLE (1u << 0)
81+
#define TRB_TOGGLE (1u << 1)
8182
#define TRB_ENT (1u << 1)
8283
#define TRB_ISP (1u << 2)
8384
#define TRB_NS (1u << 3)
@@ -94,18 +95,8 @@ struct usb_ep {
9495
#define PORTSC_PRC (1u << 21) /* Port Reset Change */
9596
#define PORTSC_PLC (1u << 22) /* Port Link State Change */
9697
#define PORTSC_CEC (1u << 23) /* Port Config Error Change */
97-
#define PORTSC_PED (1u <<1) /* Port enable/disable */
9898

99-
#define PORTSC_RW1C_MASK (PORTSC_CSC | PORTSC_PEC | PORTSC_WRC | \
100-
PORTSC_OCC | PORTSC_PRC | PORTSC_PLC | PORTSC_CEC)
101-
102-
#define XHCI_OP_USBCMD 0x00
103-
#define XHCI_OP_USBSTS 0x04
104-
105-
#define XHCI_DNCTRL 0x14
106-
107-
/* Toggle Cycle (TC) for Link TRBs (matches xHCI spec & libpayload usage) */
108-
#define TRB_TOGGLE (1u << 1)
99+
#define PORTSC_RW1C_MASK (PORTSC_CSC | PORTSC_PEC | PORTSC_WRC | PORTSC_OCC | PORTSC_PRC | PORTSC_PLC | PORTSC_CEC)
109100

110101
/* helper macros to build TRB fields */
111102
#define TRB_SET_TYPE(x) ((uint32_t)((x) & 0x3Fu) << 10)
@@ -210,7 +201,7 @@ struct xhci_hc {
210201
int speed;
211202

212203
uint8_t *ctrl_dma; // low-memory bounce for ctrl DATA stage
213-
uint64_t ctrl_dma_phys; // same value as virtual in your setup
204+
uint64_t ctrl_dma_phys; // same value as virtual
214205
uint16_t ctrl_dma_sz; // size of the bounce buffer
215206

216207
/* interrupt IN endpoint discovery (from config desc) */

src/keyboard.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -312,18 +312,7 @@ static void push_to_buffer(char x) {
312312
}
313313
}
314314

315-
void keyboard_handler(uint8_t isr, uint64_t errorcode, uint64_t irq, void *opaque) {
316-
317-
uint8_t st = inb(0x64);
318-
if ((st & 0x01) == 0) {
319-
return; /* no data */
320-
}
321-
if (st & 0x20) {
322-
return; /* AUX (mouse) byte pending: leave it */
323-
}
324-
325-
uint8_t sc = inb(0x60);
326-
315+
void keyboard_process_scancode_input(uint8_t sc) {
327316
if (sc == 0xE0) {
328317
escaped = true;
329318
return; /* wait for the next byte */
@@ -382,6 +371,18 @@ void keyboard_handler(uint8_t isr, uint64_t errorcode, uint64_t irq, void *opaqu
382371
}
383372
}
384373

374+
void keyboard_handler(uint8_t isr, uint64_t errorcode, uint64_t irq, void *opaque) {
375+
376+
uint8_t st = inb(0x64);
377+
if ((st & 0x01) == 0) {
378+
return; /* no data */
379+
}
380+
if (st & 0x20) {
381+
return; /* AUX (mouse) byte pending: leave it */
382+
}
383+
keyboard_process_scancode_input(inb(0x60));
384+
}
385+
385386
bool key_waiting() {
386387
return (buffer_read_ptr < buffer_write_ptr);
387388
}

src/usb/hid.c

Lines changed: 174 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,183 @@
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

40183
static 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

110247
static void hid_on_device_removed(const struct usb_dev *ud) {

0 commit comments

Comments
 (0)