Skip to content

Commit f9dcee1

Browse files
committed
Clean up the keyboard HID report
Was declaring too much output breaking boot keyboard on some devices. Got rid of the lockec-Shift LED. Added a short snooze when we get errors reading the LED state.
1 parent deb258b commit f9dcee1

File tree

5 files changed

+212
-186
lines changed

5 files changed

+212
-186
lines changed

internal/usbgadget/hid_keyboard.go

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,61 +28,50 @@ var keyboardConfig = gadgetConfigItem{
2828

2929
// Source: https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt
3030
var keyboardReportDesc = []byte{
31-
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
32-
0x09, 0x06, /* USAGE (Keyboard) */
33-
0xa1, 0x01, /* COLLECTION (Application) */
31+
/* boot mode descriptor */
32+
0x05, 0x01, /* USAGE_PAGE-global (Generic Desktop) */
33+
0x09, 0x06, /* USAGE-local (Keyboard) */
34+
0xA1, 0x01, /* COLLECTION-main (Application) */
3435

3536
/* 8 modifier bits */
36-
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
37-
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
38-
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
39-
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
40-
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
41-
0x75, 0x01, /* REPORT_SIZE (1) */
42-
0x95, 0x08, /* REPORT_COUNT (8) */
43-
0x81, 0x02, /* INPUT (Data,Var,Abs) */
37+
0x05, 0x07, /* USAGE_PAGE-global (Keyboard) */
38+
0x19, 0xe0, /* USAGE_MINIMUM-local 0xE0 (Keyboard LeftControl) */
39+
0x29, 0xe7, /* USAGE_MAXIMUM-local 0xE7 (Keyboard Right GUI) */
40+
0x15, 0x00, /* LOGICAL_MINIMUM-global (0) Modifier bit off) */
41+
0x25, 0x01, /* LOGICAL_MAXIMUM-global (1) Modifier bit on) */
42+
0x75, 0x01, /* REPORT_SIZE-global (1) one bit per modifier */
43+
0x95, 0x08, /* REPORT_COUNT-global (8) 8 total bits */
44+
0x81, 0x02, /* INPUT-main (Data,Var,Abs) Modifier bits 0-7 */
4445

4546
/* 8 bits of padding */
46-
0x95, 0x01, /* REPORT_COUNT (1) */
47-
0x75, 0x08, /* REPORT_SIZE (8) */
48-
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
47+
0x95, 0x01, /* REPORT_COUNT-global (1) one field */
48+
0x75, 0x08, /* REPORT_SIZE-global (8) */
49+
0x81, 0x03, /* INPUT-main (Cnst,Var,Abs) reserved byte */
4950

5051
/* 6 key codes for the 104 key keyboard */
51-
0x95, 0x06, /* REPORT_COUNT (6) */
52-
0x75, 0x08, /* REPORT_SIZE (8) */
53-
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
54-
0x25, 0xE7, /* LOGICAL_MAXIMUM (104-key HID) */
55-
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
56-
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
57-
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
58-
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
52+
0x95, 0x06, /* REPORT_COUNT-global (6) keycodes */
53+
0x75, 0x08, /* REPORT_SIZE-global (8) bits each (a byte) */
54+
0x15, 0x00, /* LOGICAL_MINIMUM-global (0) */
55+
0x25, 0xDF, /* LOGICAL_MAXIMUM-global 0xDF (104-key HID codes) */
56+
0x05, 0x07, /* USAGE_PAGE-global (Keyboard) */
57+
0x19, 0x00, /* USAGE_MINIMUM-local (Reserved/0) no key */
58+
0x29, 0xE7, /* USAGE_MAXIMUM-local (Keyboard Right GUI) */
59+
0x81, 0x00, /* INPUT-main (Data,Ary,Abs) array of keycodes */
5960

6061
/* LED report 5 bits for Num Lock through Kana */
61-
0x95, 0x05, /* REPORT_COUNT (5) */
62-
0x75, 0x01, /* REPORT_SIZE (1) */
63-
0x05, 0x08, /* USAGE_PAGE (LEDs) */
64-
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
65-
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
66-
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
67-
68-
/* 1 bit of padding for the Power LED (ignored) */
69-
0x95, 0x01, /* REPORT_COUNT (1) */
70-
0x75, 0x03, /* REPORT_SIZE (3) */
71-
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
72-
73-
/* LED report 1 bit for Shift */
74-
0x95, 0x01, /* REPORT_COUNT (1) */
75-
0x75, 0x01, /* REPORT_SIZE (1) */
76-
0x05, 0x08, /* USAGE_PAGE (LEDs) */
77-
0x19, 0x07, /* USAGE_MINIMUM (Shift) */
78-
0x29, 0x07, /* USAGE_MAXIMUM (Shift) */
79-
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
80-
81-
/* 1 bit of padding for the rest of the byte */
82-
0x95, 0x01, /* REPORT_COUNT (1) */
83-
0x75, 0x03, /* REPORT_SIZE (3) */
84-
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
85-
0xc0, /* END_COLLECTION */
62+
0x95, 0x05, /* REPORT_COUNT-global (5) 5 LED bits */
63+
0x75, 0x01, /* REPORT_SIZE-global (1) each 1 bit */
64+
0x05, 0x08, /* USAGE_PAGE-global (LEDs) */
65+
0x19, 0x01, /* USAGE_MINIMUM-local (Num Lock) */
66+
0x29, 0x05, /* USAGE_MAXIMUM-local (Kana) */
67+
0x91, 0x02, /* OUTPUT-main (Data,Var,Abs) bits 0-4 */
68+
69+
/* 3 bits of padding for the rest of the byte */
70+
0x95, 0x01, /* REPORT_COUNT-global (1) one field */
71+
0x75, 0x03, /* REPORT_SIZE-global (3) of three bits */
72+
0x91, 0x03, /* OUTPUT-main (Cnst,Var,Abs) bit 7 pad */
73+
74+
0xC0, /* END_COLLECTION */
8675
}
8776

8877
const (
@@ -96,9 +85,7 @@ const (
9685
KeyboardLedMaskScrollLock = 1 << 2
9786
KeyboardLedMaskCompose = 1 << 3
9887
KeyboardLedMaskKana = 1 << 4
99-
// power on/off LED is 5
100-
KeyboardLedMaskShift = 1 << 6
101-
ValidKeyboardLedMasks = KeyboardLedMaskNumLock | KeyboardLedMaskCapsLock | KeyboardLedMaskScrollLock | KeyboardLedMaskCompose | KeyboardLedMaskKana | KeyboardLedMaskShift
88+
ValidKeyboardLedMasks = KeyboardLedMaskNumLock | KeyboardLedMaskCapsLock | KeyboardLedMaskScrollLock | KeyboardLedMaskCompose | KeyboardLedMaskKana
10289
)
10390

10491
// Synchronization between LED states and CAPS LOCK, NUM LOCK, SCROLL LOCK,
@@ -111,7 +98,6 @@ type KeyboardState struct {
11198
ScrollLock bool `json:"scroll_lock"`
11299
Compose bool `json:"compose"`
113100
Kana bool `json:"kana"`
114-
Shift bool `json:"shift"` // This is not part of the main USB HID spec
115101
raw byte
116102
}
117103

@@ -128,7 +114,6 @@ func getKeyboardState(b byte) KeyboardState {
128114
ScrollLock: b&KeyboardLedMaskScrollLock != 0,
129115
Compose: b&KeyboardLedMaskCompose != 0,
130116
Kana: b&KeyboardLedMaskKana != 0,
131-
Shift: b&KeyboardLedMaskShift != 0,
132117
raw: b,
133118
}
134119
}
@@ -295,12 +280,13 @@ func (u *UsbGadget) listenKeyboardEvents() {
295280
time.Sleep(time.Second)
296281
continue
297282
}
298-
// reset the counter
283+
// reset the suppression counter
299284
u.resetLogSuppressionCounter("keyboardHidFileNil")
300285

301286
n, err := u.keyboardHidFile.Read(buf)
302287
if err != nil {
303288
u.logWithSuppression("keyboardHidFileRead", 100, &l, err, "failed to read")
289+
time.Sleep(100 * time.Millisecond) // Small backoff on read errors to avoid tight looping
304290
continue
305291
}
306292
u.resetLogSuppressionCounter("keyboardHidFileRead")

0 commit comments

Comments
 (0)