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