Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/* Copyright (c) 2024 Benjamin Tissoires
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_HUION 0x256C
11
#define PID_KAMVAS_PRO_19 0x006B
12
#define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902"
13
14
#define TEST_PREFIX "uhid test "
15
16
HID_BPF_CONFIG(
17
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19),
18
);
19
20
bool prev_was_out_of_range;
21
bool in_eraser_mode;
22
23
/*
24
* We need to amend the report descriptor for the following:
25
* - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch
26
* - the third button is reported through Invert, and we need some room to report it.
27
*
28
*/
29
static const __u8 fixed_rdesc[] = {
30
0x05, 0x0d, // Usage Page (Digitizers) 0
31
0x09, 0x02, // Usage (Pen) 2
32
0xa1, 0x01, // Collection (Application) 4
33
0x85, 0x0a, // Report ID (10) 6
34
0x09, 0x20, // Usage (Stylus) 8
35
0xa1, 0x01, // Collection (Application) 10
36
0x09, 0x42, // Usage (Tip Switch) 12
37
0x09, 0x44, // Usage (Barrel Switch) 14
38
0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */
39
0x09, 0x3c, // Usage (Invert) 18
40
0x09, 0x45, // Usage (Eraser) 20
41
0x15, 0x00, // Logical Minimum (0) 22
42
0x25, 0x01, // Logical Maximum (1) 24
43
0x75, 0x01, // Report Size (1) 26
44
0x95, 0x05, // Report Count (5) 28 /* changed (was 6) */
45
0x81, 0x02, // Input (Data,Var,Abs) 30
46
0x05, 0x09, // Usage Page (Button) /* inserted */
47
0x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */
48
0x95, 0x01, // Report Count (1) /* inserted */
49
0x81, 0x02, // Input (Data,Var,Abs) /* inserted */
50
0x05, 0x0d, // Usage Page (Digitizers) /* inserted */
51
0x09, 0x32, // Usage (In Range) 32
52
0x75, 0x01, // Report Size (1) 34
53
0x95, 0x01, // Report Count (1) 36
54
0x81, 0x02, // Input (Data,Var,Abs) 38
55
0x81, 0x03, // Input (Cnst,Var,Abs) 40
56
0x05, 0x01, // Usage Page (Generic Desktop) 42
57
0x09, 0x30, // Usage (X) 44
58
0x09, 0x31, // Usage (Y) 46
59
0x55, 0x0d, // Unit Exponent (-3) 48
60
0x65, 0x33, // Unit (EnglishLinear: in³) 50
61
0x26, 0xff, 0x7f, // Logical Maximum (32767) 52
62
0x35, 0x00, // Physical Minimum (0) 55
63
0x46, 0x00, 0x08, // Physical Maximum (2048) 57
64
0x75, 0x10, // Report Size (16) 60
65
0x95, 0x02, // Report Count (2) 62
66
0x81, 0x02, // Input (Data,Var,Abs) 64
67
0x05, 0x0d, // Usage Page (Digitizers) 66
68
0x09, 0x30, // Usage (Tip Pressure) 68
69
0x26, 0xff, 0x3f, // Logical Maximum (16383) 70
70
0x75, 0x10, // Report Size (16) 73
71
0x95, 0x01, // Report Count (1) 75
72
0x81, 0x02, // Input (Data,Var,Abs) 77
73
0x09, 0x3d, // Usage (X Tilt) 79
74
0x09, 0x3e, // Usage (Y Tilt) 81
75
0x15, 0xa6, // Logical Minimum (-90) 83
76
0x25, 0x5a, // Logical Maximum (90) 85
77
0x75, 0x08, // Report Size (8) 87
78
0x95, 0x02, // Report Count (2) 89
79
0x81, 0x02, // Input (Data,Var,Abs) 91
80
0xc0, // End Collection 93
81
0xc0, // End Collection 94
82
0x05, 0x0d, // Usage Page (Digitizers) 95
83
0x09, 0x04, // Usage (Touch Screen) 97
84
0xa1, 0x01, // Collection (Application) 99
85
0x85, 0x04, // Report ID (4) 101
86
0x09, 0x22, // Usage (Finger) 103
87
0xa1, 0x02, // Collection (Logical) 105
88
0x05, 0x0d, // Usage Page (Digitizers) 107
89
0x95, 0x01, // Report Count (1) 109
90
0x75, 0x06, // Report Size (6) 111
91
0x09, 0x51, // Usage (Contact Id) 113
92
0x15, 0x00, // Logical Minimum (0) 115
93
0x25, 0x3f, // Logical Maximum (63) 117
94
0x81, 0x02, // Input (Data,Var,Abs) 119
95
0x09, 0x42, // Usage (Tip Switch) 121
96
0x25, 0x01, // Logical Maximum (1) 123
97
0x75, 0x01, // Report Size (1) 125
98
0x95, 0x01, // Report Count (1) 127
99
0x81, 0x02, // Input (Data,Var,Abs) 129
100
0x75, 0x01, // Report Size (1) 131
101
0x95, 0x01, // Report Count (1) 133
102
0x81, 0x03, // Input (Cnst,Var,Abs) 135
103
0x05, 0x01, // Usage Page (Generic Desktop) 137
104
0x75, 0x10, // Report Size (16) 139
105
0x55, 0x0e, // Unit Exponent (-2) 141
106
0x65, 0x11, // Unit (SILinear: cm) 143
107
0x09, 0x30, // Usage (X) 145
108
0x26, 0xff, 0x7f, // Logical Maximum (32767) 147
109
0x35, 0x00, // Physical Minimum (0) 150
110
0x46, 0x15, 0x0c, // Physical Maximum (3093) 152
111
0x81, 0x42, // Input (Data,Var,Abs,Null) 155
112
0x09, 0x31, // Usage (Y) 157
113
0x26, 0xff, 0x7f, // Logical Maximum (32767) 159
114
0x46, 0xcb, 0x06, // Physical Maximum (1739) 162
115
0x81, 0x42, // Input (Data,Var,Abs,Null) 165
116
0x05, 0x0d, // Usage Page (Digitizers) 167
117
0x09, 0x30, // Usage (Tip Pressure) 169
118
0x26, 0xff, 0x1f, // Logical Maximum (8191) 171
119
0x75, 0x10, // Report Size (16) 174
120
0x95, 0x01, // Report Count (1) 176
121
0x81, 0x02, // Input (Data,Var,Abs) 178
122
0xc0, // End Collection 180
123
0x05, 0x0d, // Usage Page (Digitizers) 181
124
0x09, 0x22, // Usage (Finger) 183
125
0xa1, 0x02, // Collection (Logical) 185
126
0x05, 0x0d, // Usage Page (Digitizers) 187
127
0x95, 0x01, // Report Count (1) 189
128
0x75, 0x06, // Report Size (6) 191
129
0x09, 0x51, // Usage (Contact Id) 193
130
0x15, 0x00, // Logical Minimum (0) 195
131
0x25, 0x3f, // Logical Maximum (63) 197
132
0x81, 0x02, // Input (Data,Var,Abs) 199
133
0x09, 0x42, // Usage (Tip Switch) 201
134
0x25, 0x01, // Logical Maximum (1) 203
135
0x75, 0x01, // Report Size (1) 205
136
0x95, 0x01, // Report Count (1) 207
137
0x81, 0x02, // Input (Data,Var,Abs) 209
138
0x75, 0x01, // Report Size (1) 211
139
0x95, 0x01, // Report Count (1) 213
140
0x81, 0x03, // Input (Cnst,Var,Abs) 215
141
0x05, 0x01, // Usage Page (Generic Desktop) 217
142
0x75, 0x10, // Report Size (16) 219
143
0x55, 0x0e, // Unit Exponent (-2) 221
144
0x65, 0x11, // Unit (SILinear: cm) 223
145
0x09, 0x30, // Usage (X) 225
146
0x26, 0xff, 0x7f, // Logical Maximum (32767) 227
147
0x35, 0x00, // Physical Minimum (0) 230
148
0x46, 0x15, 0x0c, // Physical Maximum (3093) 232
149
0x81, 0x42, // Input (Data,Var,Abs,Null) 235
150
0x09, 0x31, // Usage (Y) 237
151
0x26, 0xff, 0x7f, // Logical Maximum (32767) 239
152
0x46, 0xcb, 0x06, // Physical Maximum (1739) 242
153
0x81, 0x42, // Input (Data,Var,Abs,Null) 245
154
0x05, 0x0d, // Usage Page (Digitizers) 247
155
0x09, 0x30, // Usage (Tip Pressure) 249
156
0x26, 0xff, 0x1f, // Logical Maximum (8191) 251
157
0x75, 0x10, // Report Size (16) 254
158
0x95, 0x01, // Report Count (1) 256
159
0x81, 0x02, // Input (Data,Var,Abs) 258
160
0xc0, // End Collection 260
161
0x05, 0x0d, // Usage Page (Digitizers) 261
162
0x09, 0x56, // Usage (Scan Time) 263
163
0x55, 0x00, // Unit Exponent (0) 265
164
0x65, 0x00, // Unit (None) 267
165
0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269
166
0x95, 0x01, // Report Count (1) 274
167
0x75, 0x20, // Report Size (32) 276
168
0x81, 0x02, // Input (Data,Var,Abs) 278
169
0x09, 0x54, // Usage (Contact Count) 280
170
0x25, 0x7f, // Logical Maximum (127) 282
171
0x95, 0x01, // Report Count (1) 284
172
0x75, 0x08, // Report Size (8) 286
173
0x81, 0x02, // Input (Data,Var,Abs) 288
174
0x75, 0x08, // Report Size (8) 290
175
0x95, 0x08, // Report Count (8) 292
176
0x81, 0x03, // Input (Cnst,Var,Abs) 294
177
0x85, 0x05, // Report ID (5) 296
178
0x09, 0x55, // Usage (Contact Max) 298
179
0x25, 0x0a, // Logical Maximum (10) 300
180
0x75, 0x08, // Report Size (8) 302
181
0x95, 0x01, // Report Count (1) 304
182
0xb1, 0x02, // Feature (Data,Var,Abs) 306
183
0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308
184
0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311
185
0x85, 0x06, // Report ID (6) 313
186
0x15, 0x00, // Logical Minimum (0) 315
187
0x26, 0xff, 0x00, // Logical Maximum (255) 317
188
0x75, 0x08, // Report Size (8) 320
189
0x96, 0x00, 0x01, // Report Count (256) 322
190
0xb1, 0x02, // Feature (Data,Var,Abs) 325
191
0xc0, // End Collection 327
192
/* New in Firmware Version: HUION_M220_240524 */
193
0x05, 0x01, // Usage Page (Generic Desktop) 328
194
0x09, 0x01, // Usage (Pointer) 330
195
0xa1, 0x01, // Collection (Application) 332
196
0x09, 0x01, // Usage (Pointer) 334
197
0xa1, 0x00, // Collection (Physical) 336
198
0x05, 0x09, // Usage Page (Button) 338
199
0x19, 0x01, // UsageMinimum (1) 340
200
0x29, 0x03, // UsageMaximum (3) 342
201
0x15, 0x00, // Logical Minimum (0) 344
202
0x25, 0x01, // Logical Maximum (1) 346
203
0x85, 0x02, // Report ID (2) 348
204
0x95, 0x03, // Report Count (3) 350
205
0x75, 0x01, // Report Size (1) 352
206
0x81, 0x02, // Input (Data,Var,Abs) 354
207
0x95, 0x01, // Report Count (1) 356
208
0x75, 0x05, // Report Size (5) 358
209
0x81, 0x01, // Input (Cnst,Arr,Abs) 360
210
0x05, 0x01, // Usage Page (Generic Desktop) 362
211
0x09, 0x30, // Usage (X) 364
212
0x09, 0x31, // Usage (Y) 366
213
0x15, 0x81, // Logical Minimum (-127) 368
214
0x25, 0x7f, // Logical Maximum (127) 370
215
0x75, 0x08, // Report Size (8) 372
216
0x95, 0x02, // Report Count (2) 374
217
0x81, 0x06, // Input (Data,Var,Rel) 376
218
0x95, 0x04, // Report Count (4) 378
219
0x75, 0x08, // Report Size (8) 380
220
0x81, 0x01, // Input (Cnst,Arr,Abs) 382
221
0xc0, // End Collection 384
222
0xc0, // End Collection 385
223
0x05, 0x0d, // Usage Page (Digitizers) 386
224
0x09, 0x05, // Usage (Touch Pad) 388
225
0xa1, 0x01, // Collection (Application) 390
226
0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 392
227
0x09, 0x0c, // Usage (Vendor Usage 0x0c) 395
228
0x15, 0x00, // Logical Minimum (0) 397
229
0x26, 0xff, 0x00, // Logical Maximum (255) 399
230
0x75, 0x08, // Report Size (8) 402
231
0x95, 0x10, // Report Count (16) 404
232
0x85, 0x3f, // Report ID (63) 406
233
0x81, 0x22, // Input (Data,Var,Abs,NoPref) 408
234
0xc0, // End Collection 410
235
0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 411
236
0x09, 0x0c, // Usage (Vendor Usage 0x0c) 414
237
0xa1, 0x01, // Collection (Application) 416
238
0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 418
239
0x09, 0x0c, // Usage (Vendor Usage 0x0c) 421
240
0x15, 0x00, // Logical Minimum (0) 423
241
0x26, 0xff, 0x00, // Logical Maximum (255) 425
242
0x85, 0x44, // Report ID (68) 428
243
0x75, 0x08, // Report Size (8) 430
244
0x96, 0x6b, 0x05, // Report Count (1387) 432
245
0x81, 0x00, // Input (Data,Arr,Abs) 435
246
0xc0, // End Collection 437
247
};
248
249
#define PRE_240524_RDESC_SIZE 328
250
#define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */
251
#define FW_240524_RDESC_SIZE 438
252
#define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc)
253
254
SEC(HID_BPF_RDESC_FIXUP)
255
int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx)
256
{
257
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
258
259
if (!data)
260
return 0; /* EPERM check */
261
262
if (hctx->size == FW_240524_RDESC_SIZE) {
263
__builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE);
264
return sizeof(fixed_rdesc);
265
}
266
267
__builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE);
268
269
return PRE_240524_RDESC_FIXED_SIZE;
270
}
271
272
/*
273
* This tablet reports the 3rd button through invert, but this conflict
274
* with the normal eraser mode.
275
* Fortunately, before entering eraser mode, (so Invert = 1),
276
* the tablet always sends an out-of-proximity event.
277
* So we can detect that single event and:
278
* - if there was none but the invert bit was toggled: this is the
279
* third button
280
* - if there was this out-of-proximity event, we are entering
281
* eraser mode, and we will until the next out-of-proximity.
282
*/
283
SEC(HID_BPF_DEVICE_EVENT)
284
int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx)
285
{
286
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
287
288
if (!data)
289
return 0; /* EPERM check */
290
291
if (data[0] != 0x0a) /* not the pen report ID */
292
return 0;
293
294
/* stylus is out of range */
295
if (!(data[1] & 0x40)) {
296
prev_was_out_of_range = true;
297
in_eraser_mode = false;
298
return 0;
299
}
300
301
/* going into eraser mode (Invert = 1) only happens after an
302
* out of range event
303
*/
304
if (prev_was_out_of_range && (data[1] & 0x18))
305
in_eraser_mode = true;
306
307
/* eraser mode works fine */
308
if (in_eraser_mode)
309
return 0;
310
311
/* copy the Invert bit reported for the 3rd button in bit 7 */
312
if (data[1] & 0x08)
313
data[1] |= 0x20;
314
315
/* clear Invert bit now that it was copied */
316
data[1] &= 0xf7;
317
318
prev_was_out_of_range = false;
319
320
return 0;
321
}
322
323
HID_BPF_OPS(huion_Kamvas_pro_19) = {
324
.hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas_pro_19,
325
.hid_device_event = (void *)kamvas_pro_19_fix_3rd_button,
326
};
327
328
SEC("syscall")
329
int probe(struct hid_bpf_probe_args *ctx)
330
{
331
332
ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) ||
333
(ctx->rdesc_size == FW_240524_RDESC_SIZE));
334
if (ctx->retval)
335
ctx->retval = -EINVAL;
336
337
/* ensure the kernel isn't fixed already */
338
if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */
339
ctx->retval = -EINVAL;
340
341
struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid);
342
343
if (!hctx) {
344
return ctx->retval = -EINVAL;
345
return 0;
346
}
347
348
const char *name = hctx->hid->name;
349
350
/* strip out TEST_PREFIX */
351
if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1))
352
name += sizeof(TEST_PREFIX) - 1;
353
354
if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)))
355
ctx->retval = -EINVAL;
356
357
hid_bpf_release_context(hctx);
358
359
return 0;
360
}
361
362
char _license[] SEC("license") = "GPL";
363
364