xref: /linux/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c (revision fcc79e1714e8c2b8e216dc3149812edd37884eef)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2024 Red Hat, Inc
3  */
4 
5 #include "vmlinux.h"
6 #include "hid_bpf.h"
7 #include "hid_bpf_helpers.h"
8 #include "hid_report_helpers.h"
9 #include <bpf/bpf_tracing.h>
10 
11 #define VID_HUION 0x256C
12 #define PID_INSPIROY_2_S 0x0066
13 
14 HID_BPF_CONFIG(
15 	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_2_S),
16 );
17 
18 /* Filled in by udev-hid-bpf */
19 char UDEV_PROP_HUION_FIRMWARE_ID[64];
20 
21 /* The prefix of the firmware ID we expect for this device. The full firmware
22  * string has a date suffix, e.g. HUION_T21j_221221
23  */
24 char EXPECTED_FIRMWARE_ID[] = "HUION_T21j_";
25 
26 /* How this BPF program works: the tablet has two modes, firmware mode and
27  * tablet mode. In firmware mode (out of the box) the tablet sends button events
28  * and the dial as keyboard combinations. In tablet mode it uses a vendor specific
29  * hid report to report everything instead.
30  * Depending on the mode some hid reports are never sent and the corresponding
31  * devices are mute.
32  *
33  * To switch the tablet use e.g.  https://github.com/whot/huion-switcher
34  * or one of the tools from the digimend project
35  *
36  * This BPF works for both modes. The huion-switcher tool sets the
37  * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware
38  * pad and pen reports (by making them vendor collections that are ignored).
39  * If that property is not set we fix all hidraw nodes so the tablet works in
40  * either mode though the drawback is that the device will show up twice if
41  * you bind it to all event nodes
42  *
43  * Default report descriptor for the first exposed hidraw node:
44  *
45  * # HUION Huion Tablet_H641P
46  * # Report descriptor length: 18 bytes
47  * # 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 0xFF00)   0
48  * # 0x09, 0x01,                    // Usage (Vendor Usage 0x01)                 3
49  * # 0xa1, 0x01,                    // Collection (Application)                  5
50  * # 0x85, 0x08,                    //   Report ID (8)                           7
51  * # 0x75, 0x58,                    //   Report Size (88)                        9
52  * # 0x95, 0x01,                    //   Report Count (1)                        11
53  * # 0x09, 0x01,                    //   Usage (Vendor Usage 0x01)               13
54  * # 0x81, 0x02,                    //   Input (Data,Var,Abs)                    15
55  * # 0xc0,                          // End Collection                            17
56  * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0
57  *
58  * This rdesc does nothing until the tablet is switched to raw mode, see
59  * https://github.com/whot/huion-switcher
60  *
61  *
62  * Second hidraw node is the Pen. This one sends events until the tablet is
63  * switched to raw mode, then it's mute.
64  *
65  * # Report descriptor length: 93 bytes
66  * # 0x05, 0x0d,          // Usage Page (Digitizers)                   0
67  * # 0x09, 0x02,          // Usage (Pen)                               2
68  * # 0xa1, 0x01,          // Collection (Application)                  4
69  * # 0x85, 0x0a,          //   Report ID (10)                          6
70  * # 0x09, 0x20,          //   Usage (Stylus)                          8
71  * # 0xa1, 0x01,          //   Collection (Application)                10
72  * # 0x09, 0x42,          //     Usage (Tip Switch)                    12
73  * # 0x09, 0x44,          //     Usage (Barrel Switch)                 14
74  * # 0x09, 0x45,          //     Usage (Eraser)                        16
75  * # 0x09, 0x3c,          //     Usage (Invert)                        18 <-- has no Invert eraser
76  * # 0x15, 0x00,          //     Logical Minimum (0)                   20
77  * # 0x25, 0x01,          //     Logical Maximum (1)                   22
78  * # 0x75, 0x01,          //     Report Size (1)                       24
79  * # 0x95, 0x06,          //     Report Count (6)                      26
80  * # 0x81, 0x02,          //     Input (Data,Var,Abs)                  28
81  * # 0x09, 0x32,          //     Usage (In Range)                      30
82  * # 0x75, 0x01,          //     Report Size (1)                       32
83  * # 0x95, 0x01,          //     Report Count (1)                      34
84  * # 0x81, 0x02,          //     Input (Data,Var,Abs)                  36
85  * # 0x81, 0x03,          //     Input (Cnst,Var,Abs)                  38
86  * # 0x05, 0x01,          //     Usage Page (Generic Desktop)          40
87  * # 0x09, 0x30,          //     Usage (X)                             42
88  * # 0x09, 0x31,          //     Usage (Y)                             44
89  * # 0x55, 0x0d,          //     Unit Exponent (-3)                    46 <-- change to -2
90  * # 0x65, 0x33,          //     Unit (EnglishLinear: in³)             48 <-- change in³ to in
91  * # 0x26, 0xff, 0x7f,    //     Logical Maximum (32767)               50
92  * # 0x35, 0x00,          //     Physical Minimum (0)                  53
93  * # 0x46, 0x00, 0x08,    //     Physical Maximum (2048)               55 <-- invalid size
94  * # 0x75, 0x10,          //     Report Size (16)                      58
95  * # 0x95, 0x02,          //     Report Count (2)                      60
96  * # 0x81, 0x02,          //     Input (Data,Var,Abs)                  62
97  * # 0x05, 0x0d,          //     Usage Page (Digitizers)               64
98  * # 0x09, 0x30,          //     Usage (Tip Pressure)                  66
99  * # 0x26, 0xff, 0x1f,    //     Logical Maximum (8191)                68
100  * # 0x75, 0x10,          //     Report Size (16)                      71
101  * # 0x95, 0x01,          //     Report Count (1)                      73
102  * # 0x81, 0x02,          //     Input (Data,Var,Abs)                  75
103  * # 0x09, 0x3d,          //     Usage (X Tilt)                        77 <-- No tilt reported
104  * # 0x09, 0x3e,          //     Usage (Y Tilt)                        79
105  * # 0x15, 0x81,          //     Logical Minimum (-127)                81
106  * # 0x25, 0x7f,          //     Logical Maximum (127)                 83
107  * # 0x75, 0x08,          //     Report Size (8)                       85
108  * # 0x95, 0x02,          //     Report Count (2)                      87
109  * # 0x81, 0x02,          //     Input (Data,Var,Abs)                  89
110  * # 0xc0,                //   End Collection                          91
111  * # 0xc0,                // End Collection                            92
112  * R: 93 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 45 09 3c 15 00 25 01 7501 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 09 3d09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0
113  *
114  * Third hidraw node is the pad which sends a combination of keyboard shortcuts until
115  * the tablet is switched to raw mode, then it's mute:
116  *
117  * # Report descriptor length: 65 bytes
118  * # 0x05, 0x01,          // Usage Page (Generic Desktop)              0
119  * # 0x09, 0x06,          // Usage (Keyboard)                          2
120  * # 0xa1, 0x01,          // Collection (Application)                  4
121  * # 0x85, 0x03,          //   Report ID (3)                           6
122  * # 0x05, 0x07,          //   Usage Page (Keyboard/Keypad)            8
123  * # 0x19, 0xe0,          //   UsageMinimum (224)                      10
124  * # 0x29, 0xe7,          //   UsageMaximum (231)                      12
125  * # 0x15, 0x00,          //   Logical Minimum (0)                     14
126  * # 0x25, 0x01,          //   Logical Maximum (1)                     16
127  * # 0x75, 0x01,          //   Report Size (1)                         18
128  * # 0x95, 0x08,          //   Report Count (8)                        20
129  * # 0x81, 0x02,          //   Input (Data,Var,Abs)                    22
130  * # 0x05, 0x07,          //   Usage Page (Keyboard/Keypad)            24
131  * # 0x19, 0x00,          //   UsageMinimum (0)                        26
132  * # 0x29, 0xff,          //   UsageMaximum (255)                      28
133  * # 0x26, 0xff, 0x00,    //   Logical Maximum (255)                   30
134  * # 0x75, 0x08,          //   Report Size (8)                         33
135  * # 0x95, 0x06,          //   Report Count (6)                        35
136  * # 0x81, 0x00,          //   Input (Data,Arr,Abs)                    37
137  * # 0xc0,                // End Collection                            39
138  * # 0x05, 0x0c,          // Usage Page (Consumer)                     40
139  * # 0x09, 0x01,          // Usage (Consumer Control)                  42
140  * # 0xa1, 0x01,          // Collection (Application)                  44
141  * # 0x85, 0x04,          //   Report ID (4)                           46
142  * # 0x19, 0x00,          //   UsageMinimum (0)                        48
143  * # 0x2a, 0x3c, 0x02,    //   UsageMaximum (572)                      50
144  * # 0x15, 0x00,          //   Logical Minimum (0)                     53
145  * # 0x26, 0x3c, 0x02,    //   Logical Maximum (572)                   55
146  * # 0x95, 0x01,          //   Report Count (1)                        58
147  * # 0x75, 0x10,          //   Report Size (16)                        60
148  * # 0x81, 0x00,          //   Input (Data,Arr,Abs)                    62
149  * # 0xc0,                // End Collection                            64
150  * R: 65 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 0507 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 00 2a 3c02 15 00 26 3c 02 95 01 75 10 81 00 c0
151  * N: HUION Huion Tablet_H641P
152  */
153 
154 #define PAD_REPORT_DESCRIPTOR_LENGTH 65
155 #define PEN_REPORT_DESCRIPTOR_LENGTH 93
156 #define VENDOR_REPORT_DESCRIPTOR_LENGTH 18
157 #define PAD_REPORT_ID 3
158 #define PEN_REPORT_ID 10
159 #define VENDOR_REPORT_ID 8
160 #define PAD_REPORT_LENGTH 8
161 #define PEN_REPORT_LENGTH 10
162 #define VENDOR_REPORT_LENGTH 12
163 
164 
165 __u8 last_button_state;
166 
167 static const __u8 fixed_rdesc_pad[] = {
168 	UsagePage_GenericDesktop
169 	Usage_GD_Keypad
170 	CollectionApplication(
171 		// -- Byte 0 in report
172 		ReportId(PAD_REPORT_ID)
173 		LogicalMinimum_i8(0)
174 		LogicalMaximum_i8(1)
175 		UsagePage_Digitizers
176 		Usage_Dig_TabletFunctionKeys
177 		CollectionPhysical(
178 			// Byte 1 in report - just exists so we get to be a tablet pad
179 			Usage_Dig_BarrelSwitch // BTN_STYLUS
180 			ReportCount(1)
181 			ReportSize(1)
182 			Input(Var|Abs)
183 			ReportCount(7) // padding
184 			Input(Const)
185 			// Bytes 2/3 in report - just exists so we get to be a tablet pad
186 			UsagePage_GenericDesktop
187 			Usage_GD_X
188 			Usage_GD_Y
189 			ReportCount(2)
190 			ReportSize(8)
191 			Input(Var|Abs)
192 			// Byte 4 in report is the wheel
193 			Usage_GD_Wheel
194 			LogicalMinimum_i8(-1)
195 			LogicalMaximum_i8(1)
196 			ReportCount(1)
197 			ReportSize(8)
198 			Input(Var|Rel)
199 			// Byte 5 is the button state
200 			UsagePage_Button
201 			UsageMinimum_i8(0x1)
202 			UsageMaximum_i8(0x6)
203 			LogicalMinimum_i8(0x1)
204 			LogicalMaximum_i8(0x6)
205 			ReportCount(1)
206 			ReportSize(8)
207 			Input(Arr|Abs)
208 		)
209 		// Make sure we match our original report length
210 		FixedSizeVendorReport(PAD_REPORT_LENGTH)
211 	)
212 };
213 
214 static const __u8 fixed_rdesc_pen[] = {
215 	UsagePage_Digitizers
216 	Usage_Dig_Pen
217 	CollectionApplication(
218 		// -- Byte 0 in report
219 		ReportId(PEN_REPORT_ID)
220 		Usage_Dig_Pen
221 		CollectionPhysical(
222 			// -- Byte 1 in report
223 			Usage_Dig_TipSwitch
224 			Usage_Dig_BarrelSwitch
225 			Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
226 			LogicalMinimum_i8(0)
227 			LogicalMaximum_i8(1)
228 			ReportSize(1)
229 			ReportCount(3)
230 			Input(Var|Abs)
231 			ReportCount(4)  // Padding
232 			Input(Const)
233 			Usage_Dig_InRange
234 			ReportCount(1)
235 			Input(Var|Abs)
236 			ReportSize(16)
237 			ReportCount(1)
238 			PushPop(
239 				UsagePage_GenericDesktop
240 				Unit(cm)
241 				UnitExponent(-1)
242 				PhysicalMinimum_i16(0)
243 				PhysicalMaximum_i16(160)
244 				LogicalMinimum_i16(0)
245 				LogicalMaximum_i16(32767)
246 				Usage_GD_X
247 				Input(Var|Abs) // Bytes 2+3
248 				PhysicalMinimum_i16(0)
249 				PhysicalMaximum_i16(100)
250 				LogicalMinimum_i16(0)
251 				LogicalMaximum_i16(32767)
252 				Usage_GD_Y
253 				Input(Var|Abs) // Bytes 4+5
254 			)
255 			UsagePage_Digitizers
256 			Usage_Dig_TipPressure
257 			LogicalMinimum_i16(0)
258 			LogicalMaximum_i16(8191)
259 			Input(Var|Abs) // Byte 6+7
260 			// Two bytes padding so we don't need to change the report at all
261 			ReportSize(8)
262 			ReportCount(2)
263 			Input(Const) // Byte 6+7
264 		)
265 	)
266 };
267 
268 static const __u8 fixed_rdesc_vendor[] = {
269 	UsagePage_Digitizers
270 	Usage_Dig_Pen
271 	CollectionApplication(
272 		// Byte 0
273 		// We leave the pen on the vendor report ID
274 		ReportId(VENDOR_REPORT_ID)
275 		Usage_Dig_Pen
276 		CollectionPhysical(
277 			// Byte 1 are the buttons
278 			LogicalMinimum_i8(0)
279 			LogicalMaximum_i8(1)
280 			ReportSize(1)
281 			Usage_Dig_TipSwitch
282 			Usage_Dig_BarrelSwitch
283 			Usage_Dig_SecondaryBarrelSwitch
284 			ReportCount(3)
285 			Input(Var|Abs)
286 			ReportCount(4) // Padding
287 			Input(Const)
288 			Usage_Dig_InRange
289 			ReportCount(1)
290 			Input(Var|Abs)
291 			ReportSize(16)
292 			ReportCount(1)
293 			PushPop(
294 				UsagePage_GenericDesktop
295 				Unit(cm)
296 				UnitExponent(-1)
297 				// Note: reported logical range differs
298 				// from the pen report ID for x and y
299 				LogicalMinimum_i16(0)
300 				LogicalMaximum_i16(32000)
301 				PhysicalMinimum_i16(0)
302 				PhysicalMaximum_i16(160)
303 				// Bytes 2/3 in report
304 				Usage_GD_X
305 				Input(Var|Abs)
306 				LogicalMinimum_i16(0)
307 				LogicalMaximum_i16(20000)
308 				PhysicalMinimum_i16(0)
309 				PhysicalMaximum_i16(100)
310 				// Bytes 4/5 in report
311 				Usage_GD_Y
312 				Input(Var|Abs)
313 			)
314 			// Bytes 6/7 in report
315 			LogicalMinimum_i16(0)
316 			LogicalMaximum_i16(8192)
317 			Usage_Dig_TipPressure
318 			Input(Var|Abs)
319 		)
320 	)
321 	UsagePage_GenericDesktop
322 	Usage_GD_Keypad
323 	CollectionApplication(
324 		// Byte 0
325 		ReportId(PAD_REPORT_ID)
326 		LogicalMinimum_i8(0)
327 		LogicalMaximum_i8(1)
328 		UsagePage_Digitizers
329 		Usage_Dig_TabletFunctionKeys
330 		CollectionPhysical(
331 			// Byte 1 are the buttons
332 			Usage_Dig_BarrelSwitch	 // BTN_STYLUS, needed so we get to be a tablet pad
333 			ReportCount(1)
334 			ReportSize(1)
335 			Input(Var|Abs)
336 			ReportCount(7) // Padding
337 			Input(Const)
338 			// Bytes 2/3 - x/y just exist so we get to be a tablet pad
339 			UsagePage_GenericDesktop
340 			Usage_GD_X
341 			Usage_GD_Y
342 			ReportCount(2)
343 			ReportSize(8)
344 			Input(Var|Abs)
345 			// Byte 4 is the button state
346 			UsagePage_Button
347 			UsageMinimum_i8(0x1)
348 			UsageMaximum_i8(0x6)
349 			LogicalMinimum_i8(0x0)
350 			LogicalMaximum_i8(0x1)
351 			ReportCount(6)
352 			ReportSize(1)
353 			Input(Var|Abs)
354 			ReportCount(2)
355 			Input(Const)
356 			// Byte 5 is the wheel
357 			UsagePage_GenericDesktop
358 			Usage_GD_Wheel
359 			LogicalMinimum_i8(-1)
360 			LogicalMaximum_i8(1)
361 			ReportCount(1)
362 			ReportSize(8)
363 			Input(Var|Rel)
364 		)
365 		// Make sure we match our original report length
366 		FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
367 	)
368 };
369 
370 static const __u8 disabled_rdesc_pen[] = {
371 	FixedSizeVendorReport(PEN_REPORT_LENGTH)
372 };
373 
374 static const __u8 disabled_rdesc_pad[] = {
375 	FixedSizeVendorReport(PAD_REPORT_LENGTH)
376 };
377 
378 SEC(HID_BPF_RDESC_FIXUP)
379 int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
380 {
381 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
382 	__s32 rdesc_size = hctx->size;
383 	__u8 have_fw_id;
384 
385 	if (!data)
386 		return 0; /* EPERM check */
387 
388 	/* If we have a firmware ID and it matches our expected prefix, we
389 	 * disable the default pad/pen nodes. They won't send events
390 	 * but cause duplicate devices.
391 	 */
392 	have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
393 				      EXPECTED_FIRMWARE_ID,
394 				      sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
395 	if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
396 		if (have_fw_id) {
397 			__builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
398 			return sizeof(disabled_rdesc_pad);
399 		}
400 
401 		__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
402 		return sizeof(fixed_rdesc_pad);
403 	}
404 	if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {
405 		if (have_fw_id) {
406 			__builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));
407 			return sizeof(disabled_rdesc_pen);
408 		}
409 
410 		__builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));
411 		return sizeof(fixed_rdesc_pen);
412 	}
413 	/* Always fix the vendor mode so the tablet will work even if nothing sets
414 	 * the udev property (e.g. huion-switcher run manually)
415 	 */
416 	if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
417 		__builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
418 		return sizeof(fixed_rdesc_vendor);
419 
420 	}
421 	return 0;
422 }
423 
424 SEC(HID_BPF_DEVICE_EVENT)
425 int BPF_PROG(inspiroy_2_fix_events, struct hid_bpf_ctx *hctx)
426 {
427 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
428 
429 	if (!data)
430 		return 0; /* EPERM check */
431 
432 	/* Only sent if tablet is in default mode */
433 	if (data[0] == PAD_REPORT_ID) {
434 		/* Nicely enough, this device only supports one button down at a time so
435 		 * the reports are easy to match. Buttons numbered from the top
436 		 *   Button released: 03 00 00 00 00 00 00 00
437 		 *   Button 1: 03 00 05 00 00 00 00 00 -> b
438 		 *   Button 2: 03 00 0c 00 00 00 00 00 -> i
439 		 *   Button 3: 03 00 08 00 00 00 00 00 -> e
440 		 *   Button 4: 03 01 16 00 00 00 00 00 -> Ctrl S
441 		 *   Button 5: 03 00 2c 00 00 00 00 00 -> space
442 		 *   Button 6: 03 05 1d 00 00 00 00 00 -> Ctrl Alt Z
443 		 *
444 		 *   Wheel down: 03 01 2d 00 00 00 00 00 -> Ctrl -
445 		 *   Wheel up:   03 01 2e 00 00 00 00 00 -> Ctrl =
446 		 */
447 		__u8 button = 0;
448 		__u8 wheel = 0;
449 
450 		switch (data[1] << 8 | data[2]) {
451 		case 0x0000:
452 			break;
453 		case 0x0005:
454 			button = 1;
455 			break;
456 		case 0x000c:
457 			button = 2;
458 			break;
459 		case 0x0008:
460 			button = 3;
461 			break;
462 		case 0x0116:
463 			button = 4;
464 			break;
465 		case 0x002c:
466 			button = 5;
467 			break;
468 		case 0x051d:
469 			button = 6;
470 			break;
471 		case 0x012d:
472 			wheel = -1;
473 			break;
474 		case 0x012e:
475 			wheel = 1;
476 			break;
477 
478 		}
479 
480 		__u8 report[6] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, wheel, button};
481 
482 		__builtin_memcpy(data, report, sizeof(report));
483 		return sizeof(report);
484 	}
485 
486 	/* Nothing to do for the PEN_REPORT_ID, it's already mapped */
487 
488 	/* Only sent if tablet is in raw mode */
489 	if (data[0] == VENDOR_REPORT_ID) {
490 		/* Pad reports */
491 		if (data[1] & 0x20) {
492 			/* See fixed_rdesc_pad */
493 			struct pad_report {
494 				__u8 report_id;
495 				__u8 btn_stylus;
496 				__u8 x;
497 				__u8 y;
498 				__u8 buttons;
499 				__u8 wheel;
500 			} __attribute__((packed)) *pad_report;
501 			__u8 wheel = 0;
502 
503 			/* Wheel report */
504 			if (data[1] == 0xf1) {
505 				if (data[5] == 2)
506 					wheel = 0xff;
507 				else
508 					wheel = data[5];
509 			} else {
510 				/* data[4] are the buttons, mapped correctly */
511 				last_button_state = data[4];
512 				wheel = 0; // wheel
513 			}
514 
515 			pad_report = (struct pad_report *)data;
516 
517 			pad_report->report_id = PAD_REPORT_ID;
518 			pad_report->btn_stylus = 0;
519 			pad_report->x = 0;
520 			pad_report->y = 0;
521 			pad_report->buttons = last_button_state;
522 			pad_report->wheel = wheel;
523 
524 			return sizeof(struct pad_report);
525 		}
526 
527 		/* Pen reports need nothing done */
528 	}
529 
530 	return 0;
531 }
532 
533 HID_BPF_OPS(inspiroy_2) = {
534 	.hid_device_event = (void *)inspiroy_2_fix_events,
535 	.hid_rdesc_fixup = (void *)hid_fix_rdesc,
536 };
537 
538 SEC("syscall")
539 int probe(struct hid_bpf_probe_args *ctx)
540 {
541 	switch (ctx->rdesc_size) {
542 	case PAD_REPORT_DESCRIPTOR_LENGTH:
543 	case PEN_REPORT_DESCRIPTOR_LENGTH:
544 	case VENDOR_REPORT_DESCRIPTOR_LENGTH:
545 		ctx->retval = 0;
546 		break;
547 	default:
548 		ctx->retval = -EINVAL;
549 	}
550 
551 	return 0;
552 }
553 
554 char _license[] SEC("license") = "GPL";
555