File Index
Files and directories
Sign in
FILE

Huion__Inspiroy-2-S.bpf.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c C
  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
 14HID_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 */
 19char 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 */
 24char 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__u8 last_tip_state;
167__u8 last_sec_barrel_state;
168__u8 force_tip_down_count;
169
170static const __u8 fixed_rdesc_pad[] = {
171	UsagePage_GenericDesktop
172	Usage_GD_Keypad
173	CollectionApplication(
174		// -- Byte 0 in report
175		ReportId(PAD_REPORT_ID)
176		LogicalMinimum_i8(0)
177		LogicalMaximum_i8(1)
178		UsagePage_Digitizers
179		Usage_Dig_TabletFunctionKeys
180		CollectionPhysical(
181			// Byte 1 in report - just exists so we get to be a tablet pad
182			Usage_Dig_BarrelSwitch // BTN_STYLUS
183			ReportCount(1)
184			ReportSize(1)
185			Input(Var|Abs)
186			ReportCount(7) // padding
187			Input(Const)
188			// Bytes 2/3 in report - just exists so we get to be a tablet pad
189			UsagePage_GenericDesktop
190			Usage_GD_X
191			Usage_GD_Y
192			ReportCount(2)
193			ReportSize(8)
194			Input(Var|Abs)
195			// Byte 4 in report is the wheel
196			Usage_GD_Wheel
197			LogicalMinimum_i8(-1)
198			LogicalMaximum_i8(1)
199			ReportCount(1)
200			ReportSize(8)
201			Input(Var|Rel)
202			// Byte 5 is the button state
203			UsagePage_Button
204			UsageMinimum_i8(0x1)
205			UsageMaximum_i8(0x6)
206			LogicalMinimum_i8(0x1)
207			LogicalMaximum_i8(0x6)
208			ReportCount(1)
209			ReportSize(8)
210			Input(Arr|Abs)
211		)
212		// Make sure we match our original report length
213		FixedSizeVendorReport(PAD_REPORT_LENGTH)
214	)
215};
216
217static const __u8 fixed_rdesc_pen[] = {
218	UsagePage_Digitizers
219	Usage_Dig_Pen
220	CollectionApplication(
221		// -- Byte 0 in report
222		ReportId(PEN_REPORT_ID)
223		Usage_Dig_Pen
224		CollectionPhysical(
225			// -- Byte 1 in report
226			Usage_Dig_TipSwitch
227			Usage_Dig_BarrelSwitch
228			Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
229			LogicalMinimum_i8(0)
230			LogicalMaximum_i8(1)
231			ReportSize(1)
232			ReportCount(3)
233			Input(Var|Abs)
234			ReportCount(4)  // Padding
235			Input(Const)
236			Usage_Dig_InRange
237			ReportCount(1)
238			Input(Var|Abs)
239			ReportSize(16)
240			ReportCount(1)
241			PushPop(
242				UsagePage_GenericDesktop
243				Unit(cm)
244				UnitExponent(-1)
245				PhysicalMinimum_i16(0)
246				PhysicalMaximum_i16(160)
247				LogicalMinimum_i16(0)
248				LogicalMaximum_i16(32767)
249				Usage_GD_X
250				Input(Var|Abs) // Bytes 2+3
251				PhysicalMinimum_i16(0)
252				PhysicalMaximum_i16(100)
253				LogicalMinimum_i16(0)
254				LogicalMaximum_i16(32767)
255				Usage_GD_Y
256				Input(Var|Abs) // Bytes 4+5
257			)
258			UsagePage_Digitizers
259			Usage_Dig_TipPressure
260			LogicalMinimum_i16(0)
261			LogicalMaximum_i16(8191)
262			Input(Var|Abs) // Byte 6+7
263			// Two bytes padding so we don't need to change the report at all
264			ReportSize(8)
265			ReportCount(2)
266			Input(Const) // Byte 6+7
267		)
268	)
269};
270
271static const __u8 fixed_rdesc_vendor[] = {
272	UsagePage_Digitizers
273	Usage_Dig_Pen
274	CollectionApplication(
275		// Byte 0
276		// We leave the pen on the vendor report ID
277		ReportId(VENDOR_REPORT_ID)
278		Usage_Dig_Pen
279		CollectionPhysical(
280			// Byte 1 are the buttons
281			LogicalMinimum_i8(0)
282			LogicalMaximum_i8(1)
283			ReportSize(1)
284			Usage_Dig_TipSwitch
285			Usage_Dig_BarrelSwitch
286			Usage_Dig_SecondaryBarrelSwitch
287			ReportCount(3)
288			Input(Var|Abs)
289			ReportCount(4) // Padding
290			Input(Const)
291			Usage_Dig_InRange
292			ReportCount(1)
293			Input(Var|Abs)
294			ReportSize(16)
295			ReportCount(1)
296			PushPop(
297				UsagePage_GenericDesktop
298				Unit(cm)
299				UnitExponent(-1)
300				// Note: reported logical range differs
301				// from the pen report ID for x and y
302				LogicalMinimum_i16(0)
303				LogicalMaximum_i16(32000)
304				PhysicalMinimum_i16(0)
305				PhysicalMaximum_i16(160)
306				// Bytes 2/3 in report
307				Usage_GD_X
308				Input(Var|Abs)
309				LogicalMinimum_i16(0)
310				LogicalMaximum_i16(20000)
311				PhysicalMinimum_i16(0)
312				PhysicalMaximum_i16(100)
313				// Bytes 4/5 in report
314				Usage_GD_Y
315				Input(Var|Abs)
316			)
317			// Bytes 6/7 in report
318			LogicalMinimum_i16(0)
319			LogicalMaximum_i16(8192)
320			Usage_Dig_TipPressure
321			Input(Var|Abs)
322		)
323	)
324	UsagePage_GenericDesktop
325	Usage_GD_Keypad
326	CollectionApplication(
327		// Byte 0
328		ReportId(PAD_REPORT_ID)
329		LogicalMinimum_i8(0)
330		LogicalMaximum_i8(1)
331		UsagePage_Digitizers
332		Usage_Dig_TabletFunctionKeys
333		CollectionPhysical(
334			// Byte 1 are the buttons
335			Usage_Dig_BarrelSwitch	 // BTN_STYLUS, needed so we get to be a tablet pad
336			ReportCount(1)
337			ReportSize(1)
338			Input(Var|Abs)
339			ReportCount(7) // Padding
340			Input(Const)
341			// Bytes 2/3 - x/y just exist so we get to be a tablet pad
342			UsagePage_GenericDesktop
343			Usage_GD_X
344			Usage_GD_Y
345			ReportCount(2)
346			ReportSize(8)
347			Input(Var|Abs)
348			// Byte 4 is the button state
349			UsagePage_Button
350			UsageMinimum_i8(0x1)
351			UsageMaximum_i8(0x6)
352			LogicalMinimum_i8(0x0)
353			LogicalMaximum_i8(0x1)
354			ReportCount(6)
355			ReportSize(1)
356			Input(Var|Abs)
357			ReportCount(2)
358			Input(Const)
359			// Byte 5 is the wheel
360			UsagePage_GenericDesktop
361			Usage_GD_Wheel
362			LogicalMinimum_i8(-1)
363			LogicalMaximum_i8(1)
364			ReportCount(1)
365			ReportSize(8)
366			Input(Var|Rel)
367		)
368		// Make sure we match our original report length
369		FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
370	)
371};
372
373static const __u8 disabled_rdesc_pen[] = {
374	FixedSizeVendorReport(PEN_REPORT_LENGTH)
375};
376
377static const __u8 disabled_rdesc_pad[] = {
378	FixedSizeVendorReport(PAD_REPORT_LENGTH)
379};
380
381SEC(HID_BPF_RDESC_FIXUP)
382int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
383{
384	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
385	__s32 rdesc_size = hctx->size;
386	__u8 have_fw_id;
387
388	if (!data)
389		return 0; /* EPERM check */
390
391	/* If we have a firmware ID and it matches our expected prefix, we
392	 * disable the default pad/pen nodes. They won't send events
393	 * but cause duplicate devices.
394	 */
395	have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
396				      EXPECTED_FIRMWARE_ID,
397				      sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
398	if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
399		if (have_fw_id) {
400			__builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
401			return sizeof(disabled_rdesc_pad);
402		}
403
404		__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
405		return sizeof(fixed_rdesc_pad);
406	}
407	if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {
408		if (have_fw_id) {
409			__builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));
410			return sizeof(disabled_rdesc_pen);
411		}
412
413		__builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));
414		return sizeof(fixed_rdesc_pen);
415	}
416	/* Always fix the vendor mode so the tablet will work even if nothing sets
417	 * the udev property (e.g. huion-switcher run manually)
418	 */
419	if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
420		__builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
421		return sizeof(fixed_rdesc_vendor);
422
423	}
424	return 0;
425}
426
427SEC(HID_BPF_DEVICE_EVENT)
428int BPF_PROG(inspiroy_2_fix_events, struct hid_bpf_ctx *hctx)
429{
430	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
431
432	if (!data)
433		return 0; /* EPERM check */
434
435	/* Only sent if tablet is in default mode */
436	if (data[0] == PAD_REPORT_ID) {
437		/* Nicely enough, this device only supports one button down at a time so
438		 * the reports are easy to match. Buttons numbered from the top
439		 *   Button released: 03 00 00 00 00 00 00 00
440		 *   Button 1: 03 00 05 00 00 00 00 00 -> b
441		 *   Button 2: 03 00 0c 00 00 00 00 00 -> i
442		 *   Button 3: 03 00 08 00 00 00 00 00 -> e
443		 *   Button 4: 03 01 16 00 00 00 00 00 -> Ctrl S
444		 *   Button 5: 03 00 2c 00 00 00 00 00 -> space
445		 *   Button 6: 03 05 1d 00 00 00 00 00 -> Ctrl Alt Z
446		 *
447		 *   Wheel down: 03 01 2d 00 00 00 00 00 -> Ctrl -
448		 *   Wheel up:   03 01 2e 00 00 00 00 00 -> Ctrl =
449		 */
450		__u8 button = 0;
451		__u8 wheel = 0;
452
453		switch (data[1] << 8 | data[2]) {
454		case 0x0000:
455			break;
456		case 0x0005:
457			button = 1;
458			break;
459		case 0x000c:
460			button = 2;
461			break;
462		case 0x0008:
463			button = 3;
464			break;
465		case 0x0116:
466			button = 4;
467			break;
468		case 0x002c:
469			button = 5;
470			break;
471		case 0x051d:
472			button = 6;
473			break;
474		case 0x012d:
475			wheel = -1;
476			break;
477		case 0x012e:
478			wheel = 1;
479			break;
480
481		}
482
483		__u8 report[6] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, wheel, button};
484
485		__builtin_memcpy(data, report, sizeof(report));
486		return sizeof(report);
487	}
488
489	/* Nothing to do for the PEN_REPORT_ID, it's already mapped */
490
491	/* Only sent if tablet is in raw mode */
492	if (data[0] == VENDOR_REPORT_ID) {
493		/* Pad reports */
494		if (data[1] & 0x20) {
495			/* See fixed_rdesc_pad */
496			struct pad_report {
497				__u8 report_id;
498				__u8 btn_stylus;
499				__u8 x;
500				__u8 y;
501				__u8 buttons;
502				__u8 wheel;
503			} __attribute__((packed)) *pad_report;
504			__u8 wheel = 0;
505
506			/* Wheel report */
507			if (data[1] == 0xf1) {
508				if (data[5] == 2)
509					wheel = 0xff;
510				else
511					wheel = data[5];
512			} else {
513				/* data[4] are the buttons, mapped correctly */
514				last_button_state = data[4];
515				wheel = 0; // wheel
516			}
517
518			pad_report = (struct pad_report *)data;
519
520			pad_report->report_id = PAD_REPORT_ID;
521			pad_report->btn_stylus = 0;
522			pad_report->x = 0;
523			pad_report->y = 0;
524			pad_report->buttons = last_button_state;
525			pad_report->wheel = wheel;
526
527			return sizeof(struct pad_report);
528		} else if (data[1] & 0x80) { /* Pen reports with InRange 1 */
529			__u8 tip_state = data[1] & 0x1;
530			__u8 sec_barrel_state = data[1] & 0x4;
531
532			if (force_tip_down_count > 0) {
533				data[1] |= 0x1;
534				--force_tip_down_count;
535				if (tip_state)
536					force_tip_down_count = 0;
537			}
538
539			/* Tip was down and we just pressed or released the
540			 * secondary barrel switch (the physical eraser
541			 * button). The device will send up to 4
542			 * reports with Tip Switch 0 and sometimes
543			 * this report has Tip Switch 0.
544			 */
545			if (last_tip_state &&
546			    last_sec_barrel_state != sec_barrel_state) {
547				force_tip_down_count = 4;
548				data[1] |= 0x1;
549			}
550			last_tip_state = tip_state;
551			last_sec_barrel_state = sec_barrel_state;
552		}
553	}
554
555	return 0;
556}
557
558HID_BPF_OPS(inspiroy_2) = {
559	.hid_device_event = (void *)inspiroy_2_fix_events,
560	.hid_rdesc_fixup = (void *)hid_fix_rdesc,
561};
562
563SEC("syscall")
564int probe(struct hid_bpf_probe_args *ctx)
565{
566	switch (ctx->rdesc_size) {
567	case PAD_REPORT_DESCRIPTOR_LENGTH:
568	case PEN_REPORT_DESCRIPTOR_LENGTH:
569	case VENDOR_REPORT_DESCRIPTOR_LENGTH:
570		ctx->retval = 0;
571		break;
572	default:
573		ctx->retval = -EINVAL;
574	}
575
576	return 0;
577}
578
579char _license[] SEC("license") = "GPL";
~/ Read-only file preview.