Skip to content

Commit 9bc0893

Browse files
author
Benjamin Tissoires
committed
HID: bpf: Fix NKRO on Mistel MD770
Mistel MD770 keyboard (using Holtek Semiconductor, Inc. controller) has a quirk in report descriptor in one of its interfaces (more detail in the source file). Fix up the descriptor to allow NKRO to work again. Tested by loading the BPF program and confirming that 8 simultaneous keypresses work. Link: https://bugzilla.kernel.org/show_bug.cgi?id=218495 Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/122 Signed-off-by: Tatsuyuki Ishi <ishitatsuyuki@gmail.com> Acked-by: Jiri Kosina <jkosina@suse.com> Link: https://patch.msgid.link/20241017-import_bpf_6-13-v2-1-6a7acb89a97f@kernel.org Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
1 parent e14e0ea commit 9bc0893

1 file changed

Lines changed: 154 additions & 0 deletions

File tree

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2024 Tatsuyuki Ishi
3+
*/
4+
5+
#include "vmlinux.h"
6+
#include "hid_bpf.h"
7+
#include "hid_bpf_helpers.h"
8+
#include <bpf/bpf_tracing.h>
9+
10+
#define VID_HOLTEK 0x04D9
11+
#define PID_MD770 0x0339
12+
#define RDESC_SIZE 203
13+
14+
HID_BPF_CONFIG(
15+
HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HOLTEK, PID_MD770)
16+
);
17+
18+
/*
19+
* The Mistel MD770 keyboard reports the first 6 simultaneous key presses
20+
* through the first interface, and anything beyond that through a second
21+
* interface. Unfortunately, the second interface's report descriptor has an
22+
* error, causing events to be malformed and ignored. This HID-BPF driver
23+
* fixes the descriptor to allow NKRO to work again.
24+
*
25+
* For reference, this is the original report descriptor:
26+
*
27+
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
28+
* 0x09, 0x80, // Usage (System Control) 2
29+
* 0xa1, 0x01, // Collection (Application) 4
30+
* 0x85, 0x01, // Report ID (1) 6
31+
* 0x19, 0x81, // Usage Minimum (129) 8
32+
* 0x29, 0x83, // Usage Maximum (131) 10
33+
* 0x15, 0x00, // Logical Minimum (0) 12
34+
* 0x25, 0x01, // Logical Maximum (1) 14
35+
* 0x95, 0x03, // Report Count (3) 16
36+
* 0x75, 0x01, // Report Size (1) 18
37+
* 0x81, 0x02, // Input (Data,Var,Abs) 20
38+
* 0x95, 0x01, // Report Count (1) 22
39+
* 0x75, 0x05, // Report Size (5) 24
40+
* 0x81, 0x01, // Input (Cnst,Arr,Abs) 26
41+
* 0xc0, // End Collection 28
42+
* 0x05, 0x0c, // Usage Page (Consumer Devices) 29
43+
* 0x09, 0x01, // Usage (Consumer Control) 31
44+
* 0xa1, 0x01, // Collection (Application) 33
45+
* 0x85, 0x02, // Report ID (2) 35
46+
* 0x15, 0x00, // Logical Minimum (0) 37
47+
* 0x25, 0x01, // Logical Maximum (1) 39
48+
* 0x95, 0x12, // Report Count (18) 41
49+
* 0x75, 0x01, // Report Size (1) 43
50+
* 0x0a, 0x83, 0x01, // Usage (AL Consumer Control Config) 45
51+
* 0x0a, 0x8a, 0x01, // Usage (AL Email Reader) 48
52+
* 0x0a, 0x92, 0x01, // Usage (AL Calculator) 51
53+
* 0x0a, 0x94, 0x01, // Usage (AL Local Machine Browser) 54
54+
* 0x09, 0xcd, // Usage (Play/Pause) 57
55+
* 0x09, 0xb7, // Usage (Stop) 59
56+
* 0x09, 0xb6, // Usage (Scan Previous Track) 61
57+
* 0x09, 0xb5, // Usage (Scan Next Track) 63
58+
* 0x09, 0xe2, // Usage (Mute) 65
59+
* 0x09, 0xea, // Usage (Volume Down) 67
60+
* 0x09, 0xe9, // Usage (Volume Up) 69
61+
* 0x0a, 0x21, 0x02, // Usage (AC Search) 71
62+
* 0x0a, 0x23, 0x02, // Usage (AC Home) 74
63+
* 0x0a, 0x24, 0x02, // Usage (AC Back) 77
64+
* 0x0a, 0x25, 0x02, // Usage (AC Forward) 80
65+
* 0x0a, 0x26, 0x02, // Usage (AC Stop) 83
66+
* 0x0a, 0x27, 0x02, // Usage (AC Refresh) 86
67+
* 0x0a, 0x2a, 0x02, // Usage (AC Bookmarks) 89
68+
* 0x81, 0x02, // Input (Data,Var,Abs) 92
69+
* 0x95, 0x01, // Report Count (1) 94
70+
* 0x75, 0x0e, // Report Size (14) 96
71+
* 0x81, 0x01, // Input (Cnst,Arr,Abs) 98
72+
* 0xc0, // End Collection 100
73+
* 0x05, 0x01, // Usage Page (Generic Desktop) 101
74+
* 0x09, 0x02, // Usage (Mouse) 103
75+
* 0xa1, 0x01, // Collection (Application) 105
76+
* 0x09, 0x01, // Usage (Pointer) 107
77+
* 0xa1, 0x00, // Collection (Physical) 109
78+
* 0x85, 0x03, // Report ID (3) 111
79+
* 0x05, 0x09, // Usage Page (Button) 113
80+
* 0x19, 0x01, // Usage Minimum (1) 115
81+
* 0x29, 0x08, // Usage Maximum (8) 117
82+
* 0x15, 0x00, // Logical Minimum (0) 119
83+
* 0x25, 0x01, // Logical Maximum (1) 121
84+
* 0x75, 0x01, // Report Size (1) 123
85+
* 0x95, 0x08, // Report Count (8) 125
86+
* 0x81, 0x02, // Input (Data,Var,Abs) 127
87+
* 0x05, 0x01, // Usage Page (Generic Desktop) 129
88+
* 0x09, 0x30, // Usage (X) 131
89+
* 0x09, 0x31, // Usage (Y) 133
90+
* 0x16, 0x01, 0x80, // Logical Minimum (-32767) 135
91+
* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 138
92+
* 0x75, 0x10, // Report Size (16) 141
93+
* 0x95, 0x02, // Report Count (2) 143
94+
* 0x81, 0x06, // Input (Data,Var,Rel) 145
95+
* 0x09, 0x38, // Usage (Wheel) 147
96+
* 0x15, 0x81, // Logical Minimum (-127) 149
97+
* 0x25, 0x7f, // Logical Maximum (127) 151
98+
* 0x75, 0x08, // Report Size (8) 153
99+
* 0x95, 0x01, // Report Count (1) 155
100+
* 0x81, 0x06, // Input (Data,Var,Rel) 157
101+
* 0x05, 0x0c, // Usage Page (Consumer Devices) 159
102+
* 0x0a, 0x38, 0x02, // Usage (AC Pan) 161
103+
* 0x95, 0x01, // Report Count (1) 164
104+
* 0x81, 0x06, // Input (Data,Var,Rel) 166
105+
* 0xc0, // End Collection 168
106+
* 0xc0, // End Collection 169
107+
* 0x05, 0x01, // Usage Page (Generic Desktop) 170
108+
* 0x09, 0x06, // Usage (Keyboard) 172
109+
* 0xa1, 0x01, // Collection (Application) 174
110+
* 0x85, 0x04, // Report ID (4) 176
111+
* 0x05, 0x07, // Usage Page (Keyboard) 178
112+
* 0x95, 0x01, // Report Count (1) 180
113+
* 0x75, 0x08, // Report Size (8) 182
114+
* 0x81, 0x03, // Input (Cnst,Var,Abs) 184
115+
* 0x95, 0xe8, // Report Count (232) 186
116+
* 0x75, 0x01, // Report Size (1) 188
117+
* 0x15, 0x00, // Logical Minimum (0) 190
118+
* 0x25, 0x01, // Logical Maximum (1) 192
119+
* 0x05, 0x07, // Usage Page (Keyboard) 194
120+
* 0x19, 0x00, // Usage Minimum (0) 196
121+
* 0x29, 0xe7, // Usage Maximum (231) 198
122+
* 0x81, 0x00, // Input (Data,Arr,Abs) 200 <- change to 0x81, 0x02 (Data,Var,Abs)
123+
* 0xc0, // End Collection 202
124+
*/
125+
126+
SEC(HID_BPF_RDESC_FIXUP)
127+
int BPF_PROG(hid_rdesc_fixup_mistel_md770, struct hid_bpf_ctx *hctx)
128+
{
129+
__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
130+
131+
if (!data)
132+
return 0; /* EPERM check */
133+
134+
if (data[201] == 0x00)
135+
data[201] = 0x02;
136+
137+
return 0;
138+
}
139+
140+
HID_BPF_OPS(mistel_md770) = {
141+
.hid_rdesc_fixup = (void *)hid_rdesc_fixup_mistel_md770,
142+
};
143+
144+
SEC("syscall")
145+
int probe(struct hid_bpf_probe_args *ctx)
146+
{
147+
ctx->retval = ctx->rdesc_size != RDESC_SIZE;
148+
if (ctx->retval)
149+
ctx->retval = -EINVAL;
150+
151+
return 0;
152+
}
153+
154+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)