19f1bf4c2SBenjamin Tissoires // SPDX-License-Identifier: GPL-2.0-only
29f1bf4c2SBenjamin Tissoires /* Copyright (c) 2024 Benjamin Tissoires
39f1bf4c2SBenjamin Tissoires */
49f1bf4c2SBenjamin Tissoires
59f1bf4c2SBenjamin Tissoires #include "vmlinux.h"
69f1bf4c2SBenjamin Tissoires #include "hid_bpf.h"
79f1bf4c2SBenjamin Tissoires #include "hid_bpf_helpers.h"
89f1bf4c2SBenjamin Tissoires #include <bpf/bpf_tracing.h>
99f1bf4c2SBenjamin Tissoires
109f1bf4c2SBenjamin Tissoires #define VID_HUION 0x256C
119f1bf4c2SBenjamin Tissoires #define PID_KAMVAS_PRO_19 0x006B
129f1bf4c2SBenjamin Tissoires #define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902"
139f1bf4c2SBenjamin Tissoires
149f1bf4c2SBenjamin Tissoires #define TEST_PREFIX "uhid test "
159f1bf4c2SBenjamin Tissoires
169f1bf4c2SBenjamin Tissoires HID_BPF_CONFIG(
179f1bf4c2SBenjamin Tissoires HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19),
189f1bf4c2SBenjamin Tissoires );
199f1bf4c2SBenjamin Tissoires
209f1bf4c2SBenjamin Tissoires bool prev_was_out_of_range;
219f1bf4c2SBenjamin Tissoires bool in_eraser_mode;
229f1bf4c2SBenjamin Tissoires
239f1bf4c2SBenjamin Tissoires /*
249f1bf4c2SBenjamin Tissoires * We need to amend the report descriptor for the following:
259f1bf4c2SBenjamin Tissoires * - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch
269f1bf4c2SBenjamin Tissoires * - the third button is reported through Invert, and we need some room to report it.
279f1bf4c2SBenjamin Tissoires *
289f1bf4c2SBenjamin Tissoires */
299f1bf4c2SBenjamin Tissoires static const __u8 fixed_rdesc[] = {
309f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 0
319f1bf4c2SBenjamin Tissoires 0x09, 0x02, // Usage (Pen) 2
329f1bf4c2SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 4
339f1bf4c2SBenjamin Tissoires 0x85, 0x0a, // Report ID (10) 6
349f1bf4c2SBenjamin Tissoires 0x09, 0x20, // Usage (Stylus) 8
359f1bf4c2SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 10
369f1bf4c2SBenjamin Tissoires 0x09, 0x42, // Usage (Tip Switch) 12
379f1bf4c2SBenjamin Tissoires 0x09, 0x44, // Usage (Barrel Switch) 14
389f1bf4c2SBenjamin Tissoires 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */
399f1bf4c2SBenjamin Tissoires 0x09, 0x3c, // Usage (Invert) 18
409f1bf4c2SBenjamin Tissoires 0x09, 0x45, // Usage (Eraser) 20
419f1bf4c2SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 22
429f1bf4c2SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 24
439f1bf4c2SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 26
44*531a1cc6SBenjamin Tissoires 0x95, 0x05, // Report Count (5) 28 /* changed (was 6) */
459f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 30
469f1bf4c2SBenjamin Tissoires 0x05, 0x09, // Usage Page (Button) /* inserted */
479f1bf4c2SBenjamin Tissoires 0x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */
489f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) /* inserted */
499f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) /* inserted */
509f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) /* inserted */
519f1bf4c2SBenjamin Tissoires 0x09, 0x32, // Usage (In Range) 32
529f1bf4c2SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 34
539f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 36
549f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 38
559f1bf4c2SBenjamin Tissoires 0x81, 0x03, // Input (Cnst,Var,Abs) 40
569f1bf4c2SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 42
579f1bf4c2SBenjamin Tissoires 0x09, 0x30, // Usage (X) 44
589f1bf4c2SBenjamin Tissoires 0x09, 0x31, // Usage (Y) 46
599f1bf4c2SBenjamin Tissoires 0x55, 0x0d, // Unit Exponent (-3) 48
609f1bf4c2SBenjamin Tissoires 0x65, 0x33, // Unit (EnglishLinear: in³) 50
619f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52
629f1bf4c2SBenjamin Tissoires 0x35, 0x00, // Physical Minimum (0) 55
639f1bf4c2SBenjamin Tissoires 0x46, 0x00, 0x08, // Physical Maximum (2048) 57
649f1bf4c2SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 60
659f1bf4c2SBenjamin Tissoires 0x95, 0x02, // Report Count (2) 62
669f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 64
679f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 66
689f1bf4c2SBenjamin Tissoires 0x09, 0x30, // Usage (Tip Pressure) 68
699f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70
709f1bf4c2SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 73
719f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 75
729f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 77
739f1bf4c2SBenjamin Tissoires 0x09, 0x3d, // Usage (X Tilt) 79
749f1bf4c2SBenjamin Tissoires 0x09, 0x3e, // Usage (Y Tilt) 81
759f1bf4c2SBenjamin Tissoires 0x15, 0xa6, // Logical Minimum (-90) 83
769f1bf4c2SBenjamin Tissoires 0x25, 0x5a, // Logical Maximum (90) 85
779f1bf4c2SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 87
789f1bf4c2SBenjamin Tissoires 0x95, 0x02, // Report Count (2) 89
799f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 91
809f1bf4c2SBenjamin Tissoires 0xc0, // End Collection 93
819f1bf4c2SBenjamin Tissoires 0xc0, // End Collection 94
829f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 95
839f1bf4c2SBenjamin Tissoires 0x09, 0x04, // Usage (Touch Screen) 97
849f1bf4c2SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 99
859f1bf4c2SBenjamin Tissoires 0x85, 0x04, // Report ID (4) 101
869f1bf4c2SBenjamin Tissoires 0x09, 0x22, // Usage (Finger) 103
879f1bf4c2SBenjamin Tissoires 0xa1, 0x02, // Collection (Logical) 105
889f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 107
899f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 109
909f1bf4c2SBenjamin Tissoires 0x75, 0x06, // Report Size (6) 111
919f1bf4c2SBenjamin Tissoires 0x09, 0x51, // Usage (Contact Id) 113
929f1bf4c2SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 115
939f1bf4c2SBenjamin Tissoires 0x25, 0x3f, // Logical Maximum (63) 117
949f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 119
959f1bf4c2SBenjamin Tissoires 0x09, 0x42, // Usage (Tip Switch) 121
969f1bf4c2SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 123
979f1bf4c2SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 125
989f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 127
999f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 129
1009f1bf4c2SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 131
1019f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 133
1029f1bf4c2SBenjamin Tissoires 0x81, 0x03, // Input (Cnst,Var,Abs) 135
1039f1bf4c2SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 137
1049f1bf4c2SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 139
1059f1bf4c2SBenjamin Tissoires 0x55, 0x0e, // Unit Exponent (-2) 141
1069f1bf4c2SBenjamin Tissoires 0x65, 0x11, // Unit (SILinear: cm) 143
1079f1bf4c2SBenjamin Tissoires 0x09, 0x30, // Usage (X) 145
1089f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147
1099f1bf4c2SBenjamin Tissoires 0x35, 0x00, // Physical Minimum (0) 150
1109f1bf4c2SBenjamin Tissoires 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152
1119f1bf4c2SBenjamin Tissoires 0x81, 0x42, // Input (Data,Var,Abs,Null) 155
1129f1bf4c2SBenjamin Tissoires 0x09, 0x31, // Usage (Y) 157
1139f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159
1149f1bf4c2SBenjamin Tissoires 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162
1159f1bf4c2SBenjamin Tissoires 0x81, 0x42, // Input (Data,Var,Abs,Null) 165
1169f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 167
1179f1bf4c2SBenjamin Tissoires 0x09, 0x30, // Usage (Tip Pressure) 169
1189f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171
1199f1bf4c2SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 174
1209f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 176
1219f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 178
1229f1bf4c2SBenjamin Tissoires 0xc0, // End Collection 180
1239f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 181
1249f1bf4c2SBenjamin Tissoires 0x09, 0x22, // Usage (Finger) 183
1259f1bf4c2SBenjamin Tissoires 0xa1, 0x02, // Collection (Logical) 185
1269f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 187
1279f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 189
1289f1bf4c2SBenjamin Tissoires 0x75, 0x06, // Report Size (6) 191
1299f1bf4c2SBenjamin Tissoires 0x09, 0x51, // Usage (Contact Id) 193
1309f1bf4c2SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 195
1319f1bf4c2SBenjamin Tissoires 0x25, 0x3f, // Logical Maximum (63) 197
1329f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 199
1339f1bf4c2SBenjamin Tissoires 0x09, 0x42, // Usage (Tip Switch) 201
1349f1bf4c2SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 203
1359f1bf4c2SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 205
1369f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 207
1379f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 209
1389f1bf4c2SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 211
1399f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 213
1409f1bf4c2SBenjamin Tissoires 0x81, 0x03, // Input (Cnst,Var,Abs) 215
1419f1bf4c2SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 217
1429f1bf4c2SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 219
1439f1bf4c2SBenjamin Tissoires 0x55, 0x0e, // Unit Exponent (-2) 221
1449f1bf4c2SBenjamin Tissoires 0x65, 0x11, // Unit (SILinear: cm) 223
1459f1bf4c2SBenjamin Tissoires 0x09, 0x30, // Usage (X) 225
1469f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227
1479f1bf4c2SBenjamin Tissoires 0x35, 0x00, // Physical Minimum (0) 230
1489f1bf4c2SBenjamin Tissoires 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232
1499f1bf4c2SBenjamin Tissoires 0x81, 0x42, // Input (Data,Var,Abs,Null) 235
1509f1bf4c2SBenjamin Tissoires 0x09, 0x31, // Usage (Y) 237
1519f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239
1529f1bf4c2SBenjamin Tissoires 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242
1539f1bf4c2SBenjamin Tissoires 0x81, 0x42, // Input (Data,Var,Abs,Null) 245
1549f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 247
1559f1bf4c2SBenjamin Tissoires 0x09, 0x30, // Usage (Tip Pressure) 249
1569f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251
1579f1bf4c2SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 254
1589f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 256
1599f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 258
1609f1bf4c2SBenjamin Tissoires 0xc0, // End Collection 260
1619f1bf4c2SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 261
1629f1bf4c2SBenjamin Tissoires 0x09, 0x56, // Usage (Scan Time) 263
1639f1bf4c2SBenjamin Tissoires 0x55, 0x00, // Unit Exponent (0) 265
1649f1bf4c2SBenjamin Tissoires 0x65, 0x00, // Unit (None) 267
1659f1bf4c2SBenjamin Tissoires 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269
1669f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 274
1679f1bf4c2SBenjamin Tissoires 0x75, 0x20, // Report Size (32) 276
1689f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 278
1699f1bf4c2SBenjamin Tissoires 0x09, 0x54, // Usage (Contact Count) 280
1709f1bf4c2SBenjamin Tissoires 0x25, 0x7f, // Logical Maximum (127) 282
1719f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 284
1729f1bf4c2SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 286
1739f1bf4c2SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 288
1749f1bf4c2SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 290
1759f1bf4c2SBenjamin Tissoires 0x95, 0x08, // Report Count (8) 292
1769f1bf4c2SBenjamin Tissoires 0x81, 0x03, // Input (Cnst,Var,Abs) 294
1779f1bf4c2SBenjamin Tissoires 0x85, 0x05, // Report ID (5) 296
1789f1bf4c2SBenjamin Tissoires 0x09, 0x55, // Usage (Contact Max) 298
1799f1bf4c2SBenjamin Tissoires 0x25, 0x0a, // Logical Maximum (10) 300
1809f1bf4c2SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 302
1819f1bf4c2SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 304
1829f1bf4c2SBenjamin Tissoires 0xb1, 0x02, // Feature (Data,Var,Abs) 306
1839f1bf4c2SBenjamin Tissoires 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308
1849f1bf4c2SBenjamin Tissoires 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311
1859f1bf4c2SBenjamin Tissoires 0x85, 0x06, // Report ID (6) 313
1869f1bf4c2SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 315
1879f1bf4c2SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 317
1889f1bf4c2SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 320
1899f1bf4c2SBenjamin Tissoires 0x96, 0x00, 0x01, // Report Count (256) 322
1909f1bf4c2SBenjamin Tissoires 0xb1, 0x02, // Feature (Data,Var,Abs) 325
1919f1bf4c2SBenjamin Tissoires 0xc0, // End Collection 327
192*531a1cc6SBenjamin Tissoires /* New in Firmware Version: HUION_M220_240524 */
193*531a1cc6SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 328
194*531a1cc6SBenjamin Tissoires 0x09, 0x01, // Usage (Pointer) 330
195*531a1cc6SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 332
196*531a1cc6SBenjamin Tissoires 0x09, 0x01, // Usage (Pointer) 334
197*531a1cc6SBenjamin Tissoires 0xa1, 0x00, // Collection (Physical) 336
198*531a1cc6SBenjamin Tissoires 0x05, 0x09, // Usage Page (Button) 338
199*531a1cc6SBenjamin Tissoires 0x19, 0x01, // UsageMinimum (1) 340
200*531a1cc6SBenjamin Tissoires 0x29, 0x03, // UsageMaximum (3) 342
201*531a1cc6SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 344
202*531a1cc6SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 346
203*531a1cc6SBenjamin Tissoires 0x85, 0x02, // Report ID (2) 348
204*531a1cc6SBenjamin Tissoires 0x95, 0x03, // Report Count (3) 350
205*531a1cc6SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 352
206*531a1cc6SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 354
207*531a1cc6SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 356
208*531a1cc6SBenjamin Tissoires 0x75, 0x05, // Report Size (5) 358
209*531a1cc6SBenjamin Tissoires 0x81, 0x01, // Input (Cnst,Arr,Abs) 360
210*531a1cc6SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 362
211*531a1cc6SBenjamin Tissoires 0x09, 0x30, // Usage (X) 364
212*531a1cc6SBenjamin Tissoires 0x09, 0x31, // Usage (Y) 366
213*531a1cc6SBenjamin Tissoires 0x15, 0x81, // Logical Minimum (-127) 368
214*531a1cc6SBenjamin Tissoires 0x25, 0x7f, // Logical Maximum (127) 370
215*531a1cc6SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 372
216*531a1cc6SBenjamin Tissoires 0x95, 0x02, // Report Count (2) 374
217*531a1cc6SBenjamin Tissoires 0x81, 0x06, // Input (Data,Var,Rel) 376
218*531a1cc6SBenjamin Tissoires 0x95, 0x04, // Report Count (4) 378
219*531a1cc6SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 380
220*531a1cc6SBenjamin Tissoires 0x81, 0x01, // Input (Cnst,Arr,Abs) 382
221*531a1cc6SBenjamin Tissoires 0xc0, // End Collection 384
222*531a1cc6SBenjamin Tissoires 0xc0, // End Collection 385
223*531a1cc6SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 386
224*531a1cc6SBenjamin Tissoires 0x09, 0x05, // Usage (Touch Pad) 388
225*531a1cc6SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 390
226*531a1cc6SBenjamin Tissoires 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 392
227*531a1cc6SBenjamin Tissoires 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 395
228*531a1cc6SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 397
229*531a1cc6SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 399
230*531a1cc6SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 402
231*531a1cc6SBenjamin Tissoires 0x95, 0x10, // Report Count (16) 404
232*531a1cc6SBenjamin Tissoires 0x85, 0x3f, // Report ID (63) 406
233*531a1cc6SBenjamin Tissoires 0x81, 0x22, // Input (Data,Var,Abs,NoPref) 408
234*531a1cc6SBenjamin Tissoires 0xc0, // End Collection 410
235*531a1cc6SBenjamin Tissoires 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 411
236*531a1cc6SBenjamin Tissoires 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 414
237*531a1cc6SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 416
238*531a1cc6SBenjamin Tissoires 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 418
239*531a1cc6SBenjamin Tissoires 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 421
240*531a1cc6SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 423
241*531a1cc6SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 425
242*531a1cc6SBenjamin Tissoires 0x85, 0x44, // Report ID (68) 428
243*531a1cc6SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 430
244*531a1cc6SBenjamin Tissoires 0x96, 0x6b, 0x05, // Report Count (1387) 432
245*531a1cc6SBenjamin Tissoires 0x81, 0x00, // Input (Data,Arr,Abs) 435
246*531a1cc6SBenjamin Tissoires 0xc0, // End Collection 437
2479f1bf4c2SBenjamin Tissoires };
2489f1bf4c2SBenjamin Tissoires
249*531a1cc6SBenjamin Tissoires #define PRE_240524_RDESC_SIZE 328
250*531a1cc6SBenjamin Tissoires #define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */
251*531a1cc6SBenjamin Tissoires #define FW_240524_RDESC_SIZE 438
252*531a1cc6SBenjamin Tissoires #define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc)
253*531a1cc6SBenjamin Tissoires
SEC(HID_BPF_RDESC_FIXUP)254df67602fSBenjamin Tissoires SEC(HID_BPF_RDESC_FIXUP)
2559f1bf4c2SBenjamin Tissoires int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx)
2569f1bf4c2SBenjamin Tissoires {
2579f1bf4c2SBenjamin Tissoires __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
2589f1bf4c2SBenjamin Tissoires
2599f1bf4c2SBenjamin Tissoires if (!data)
2609f1bf4c2SBenjamin Tissoires return 0; /* EPERM check */
2619f1bf4c2SBenjamin Tissoires
262*531a1cc6SBenjamin Tissoires if (hctx->size == FW_240524_RDESC_SIZE) {
263*531a1cc6SBenjamin Tissoires __builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE);
2649f1bf4c2SBenjamin Tissoires return sizeof(fixed_rdesc);
2659f1bf4c2SBenjamin Tissoires }
2669f1bf4c2SBenjamin Tissoires
267*531a1cc6SBenjamin Tissoires __builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE);
268*531a1cc6SBenjamin Tissoires
269*531a1cc6SBenjamin Tissoires return PRE_240524_RDESC_FIXED_SIZE;
270*531a1cc6SBenjamin Tissoires }
271*531a1cc6SBenjamin Tissoires
2729f1bf4c2SBenjamin Tissoires /*
2739f1bf4c2SBenjamin Tissoires * This tablet reports the 3rd button through invert, but this conflict
2749f1bf4c2SBenjamin Tissoires * with the normal eraser mode.
2759f1bf4c2SBenjamin Tissoires * Fortunately, before entering eraser mode, (so Invert = 1),
2769f1bf4c2SBenjamin Tissoires * the tablet always sends an out-of-proximity event.
2779f1bf4c2SBenjamin Tissoires * So we can detect that single event and:
2789f1bf4c2SBenjamin Tissoires * - if there was none but the invert bit was toggled: this is the
2799f1bf4c2SBenjamin Tissoires * third button
2809f1bf4c2SBenjamin Tissoires * - if there was this out-of-proximity event, we are entering
2819f1bf4c2SBenjamin Tissoires * eraser mode, and we will until the next out-of-proximity.
2829f1bf4c2SBenjamin Tissoires */
SEC(HID_BPF_DEVICE_EVENT)283df67602fSBenjamin Tissoires SEC(HID_BPF_DEVICE_EVENT)
2849f1bf4c2SBenjamin Tissoires int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx)
2859f1bf4c2SBenjamin Tissoires {
2869f1bf4c2SBenjamin Tissoires __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
2879f1bf4c2SBenjamin Tissoires
2889f1bf4c2SBenjamin Tissoires if (!data)
2899f1bf4c2SBenjamin Tissoires return 0; /* EPERM check */
2909f1bf4c2SBenjamin Tissoires
2919f1bf4c2SBenjamin Tissoires if (data[0] != 0x0a) /* not the pen report ID */
2929f1bf4c2SBenjamin Tissoires return 0;
2939f1bf4c2SBenjamin Tissoires
2949f1bf4c2SBenjamin Tissoires /* stylus is out of range */
2959f1bf4c2SBenjamin Tissoires if (!(data[1] & 0x40)) {
2969f1bf4c2SBenjamin Tissoires prev_was_out_of_range = true;
2979f1bf4c2SBenjamin Tissoires in_eraser_mode = false;
2989f1bf4c2SBenjamin Tissoires return 0;
2999f1bf4c2SBenjamin Tissoires }
3009f1bf4c2SBenjamin Tissoires
3019f1bf4c2SBenjamin Tissoires /* going into eraser mode (Invert = 1) only happens after an
3029f1bf4c2SBenjamin Tissoires * out of range event
3039f1bf4c2SBenjamin Tissoires */
3049f1bf4c2SBenjamin Tissoires if (prev_was_out_of_range && (data[1] & 0x18))
3059f1bf4c2SBenjamin Tissoires in_eraser_mode = true;
3069f1bf4c2SBenjamin Tissoires
3079f1bf4c2SBenjamin Tissoires /* eraser mode works fine */
3089f1bf4c2SBenjamin Tissoires if (in_eraser_mode)
3099f1bf4c2SBenjamin Tissoires return 0;
3109f1bf4c2SBenjamin Tissoires
3119f1bf4c2SBenjamin Tissoires /* copy the Invert bit reported for the 3rd button in bit 7 */
3129f1bf4c2SBenjamin Tissoires if (data[1] & 0x08)
3139f1bf4c2SBenjamin Tissoires data[1] |= 0x20;
3149f1bf4c2SBenjamin Tissoires
3159f1bf4c2SBenjamin Tissoires /* clear Invert bit now that it was copied */
3169f1bf4c2SBenjamin Tissoires data[1] &= 0xf7;
3179f1bf4c2SBenjamin Tissoires
3189f1bf4c2SBenjamin Tissoires prev_was_out_of_range = false;
3199f1bf4c2SBenjamin Tissoires
3209f1bf4c2SBenjamin Tissoires return 0;
3219f1bf4c2SBenjamin Tissoires }
3229f1bf4c2SBenjamin Tissoires
32350fe0fc6SBenjamin Tissoires HID_BPF_OPS(huion_Kamvas_pro_19) = {
32450fe0fc6SBenjamin Tissoires .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas_pro_19,
32550fe0fc6SBenjamin Tissoires .hid_device_event = (void *)kamvas_pro_19_fix_3rd_button,
32650fe0fc6SBenjamin Tissoires };
32750fe0fc6SBenjamin Tissoires
3289f1bf4c2SBenjamin Tissoires SEC("syscall")
probe(struct hid_bpf_probe_args * ctx)3299f1bf4c2SBenjamin Tissoires int probe(struct hid_bpf_probe_args *ctx)
3309f1bf4c2SBenjamin Tissoires {
331*531a1cc6SBenjamin Tissoires
332*531a1cc6SBenjamin Tissoires ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) ||
333*531a1cc6SBenjamin Tissoires (ctx->rdesc_size == FW_240524_RDESC_SIZE));
3349f1bf4c2SBenjamin Tissoires if (ctx->retval)
3359f1bf4c2SBenjamin Tissoires ctx->retval = -EINVAL;
3369f1bf4c2SBenjamin Tissoires
3379f1bf4c2SBenjamin Tissoires /* ensure the kernel isn't fixed already */
3389f1bf4c2SBenjamin Tissoires if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */
3399f1bf4c2SBenjamin Tissoires ctx->retval = -EINVAL;
3409f1bf4c2SBenjamin Tissoires
3419f1bf4c2SBenjamin Tissoires struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid);
3429f1bf4c2SBenjamin Tissoires
3439f1bf4c2SBenjamin Tissoires if (!hctx) {
3449f1bf4c2SBenjamin Tissoires return ctx->retval = -EINVAL;
3459f1bf4c2SBenjamin Tissoires return 0;
3469f1bf4c2SBenjamin Tissoires }
3479f1bf4c2SBenjamin Tissoires
3489f1bf4c2SBenjamin Tissoires const char *name = hctx->hid->name;
3499f1bf4c2SBenjamin Tissoires
3509f1bf4c2SBenjamin Tissoires /* strip out TEST_PREFIX */
3519f1bf4c2SBenjamin Tissoires if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1))
3529f1bf4c2SBenjamin Tissoires name += sizeof(TEST_PREFIX) - 1;
3539f1bf4c2SBenjamin Tissoires
3549f1bf4c2SBenjamin Tissoires if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)))
3559f1bf4c2SBenjamin Tissoires ctx->retval = -EINVAL;
3569f1bf4c2SBenjamin Tissoires
3579f1bf4c2SBenjamin Tissoires hid_bpf_release_context(hctx);
3589f1bf4c2SBenjamin Tissoires
3599f1bf4c2SBenjamin Tissoires return 0;
3609f1bf4c2SBenjamin Tissoires }
3619f1bf4c2SBenjamin Tissoires
3629f1bf4c2SBenjamin Tissoires char _license[] SEC("license") = "GPL";
363