brintos

brintos / linux-shallow public Read only

0
0
Text · 22.5 KiB · 2411dec Raw
615 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2024 Red Hat, Inc3 */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 0x256C12#define PID_DIAL_2 0x006013 14 15HID_BPF_CONFIG(16	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_DIAL_2),17);18 19/* Filled in by udev-hid-bpf */20char UDEV_PROP_HUION_FIRMWARE_ID[64];21 22/* The prefix of the firmware ID we expect for this device. The full firmware23 * string has a date suffix, e.g. HUION_T21j_22122124 */25char EXPECTED_FIRMWARE_ID[] = "HUION_T216_";26 27/* How this BPF program works: the tablet has two modes, firmware mode and28 * tablet mode. In firmware mode (out of the box) the tablet sends button events29 * and the dial as keyboard combinations. In tablet mode it uses a vendor specific30 * hid report to report everything instead.31 * Depending on the mode some hid reports are never sent and the corresponding32 * devices are mute.33 *34 * To switch the tablet use e.g.  https://github.com/whot/huion-switcher35 * or one of the tools from the digimend project36 *37 * This BPF works for both modes. The huion-switcher tool sets the38 * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware39 * pad and pen reports (by making them vendor collections that are ignored).40 * If that property is not set we fix all hidraw nodes so the tablet works in41 * either mode though the drawback is that the device will show up twice if42 * you bind it to all event nodes43 *44 * Default report descriptor for the first exposed hidraw node:45 *46 * # HUION Huion Tablet_Q630M47 * # 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 1)  048 * # 0x09, 0x01,                    // Usage (Vendor Usage 1)              349 * # 0xa1, 0x01,                    // Collection (Application)            550 * # 0x85, 0x08,                    //  Report ID (8)                      751 * # 0x75, 0x58,                    //  Report Size (88)                   952 * # 0x95, 0x01,                    //  Report Count (1)                   1153 * # 0x09, 0x01,                    //  Usage (Vendor Usage 1)             1354 * # 0x81, 0x02,                    //  Input (Data,Var,Abs)               1555 * # 0xc0,                          // End Collection                      1756 * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c057 *58 * This rdesc does nothing until the tablet is switched to raw mode, see59 * https://github.com/whot/huion-switcher60 *61 *62 * Second hidraw node is the Pen. This one sends events until the tablet is63 * switched to raw mode, then it's mute.64 *65 * # Report descriptor length: 93 bytes66 * # HUION Huion Tablet_Q630M67 * # 0x05, 0x0d,                    // Usage Page (Digitizers)             068 * # 0x09, 0x02,                    // Usage (Pen)                         269 * # 0xa1, 0x01,                    // Collection (Application)            470 * # 0x85, 0x0a,                    //  Report ID (10)                     671 * # 0x09, 0x20,                    //  Usage (Stylus)                     872 * # 0xa1, 0x01,                    //  Collection (Application)           1073 * # 0x09, 0x42,                    //   Usage (Tip Switch)                1274 * # 0x09, 0x44,                    //   Usage (Barrel Switch)             1475 * # 0x09, 0x45,                    //   Usage (Eraser)                    1676 * # 0x09, 0x3c,                    //   Usage (Invert)                    1877 * # 0x15, 0x00,                    //   Logical Minimum (0)               2078 * # 0x25, 0x01,                    //   Logical Maximum (1)               2279 * # 0x75, 0x01,                    //   Report Size (1)                   2480 * # 0x95, 0x06,                    //   Report Count (6)                  2681 * # 0x81, 0x02,                    //   Input (Data,Var,Abs)              2882 * # 0x09, 0x32,                    //   Usage (In Range)                  3083 * # 0x75, 0x01,                    //   Report Size (1)                   3284 * # 0x95, 0x01,                    //   Report Count (1)                  3485 * # 0x81, 0x02,                    //   Input (Data,Var,Abs)              3686 * # 0x81, 0x03,                    //   Input (Cnst,Var,Abs)              3887 * # 0x05, 0x01,                    //   Usage Page (Generic Desktop)      4088 * # 0x09, 0x30,                    //   Usage (X)                         4289 * # 0x09, 0x31,                    //   Usage (Y)                         4490 * # 0x55, 0x0d,                    //   Unit Exponent (-3)                4691 * # 0x65, 0x33,                    //   Unit (EnglishLinear: in³)         4892 * # 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           5093 * # 0x35, 0x00,                    //   Physical Minimum (0)              5394 * # 0x46, 0x00, 0x08,              //   Physical Maximum (2048)           5595 * # 0x75, 0x10,                    //   Report Size (16)                  5896 * # 0x95, 0x02,                    //   Report Count (2)                  6097 * # 0x81, 0x02,                    //   Input (Data,Var,Abs)              6298 * # 0x05, 0x0d,                    //   Usage Page (Digitizers)           6499 * # 0x09, 0x30,                    //   Usage (Tip Pressure)              66100 * # 0x26, 0xff, 0x1f,              //   Logical Maximum (8191)            68101 * # 0x75, 0x10,                    //   Report Size (16)                  71102 * # 0x95, 0x01,                    //   Report Count (1)                  73103 * # 0x81, 0x02,                    //   Input (Data,Var,Abs)              75104 * # 0x09, 0x3d,                    //   Usage (X Tilt)                    77105 * # 0x09, 0x3e,                    //   Usage (Y Tilt)                    79106 * # 0x15, 0x81,                    //   Logical Minimum (-127)            81107 * # 0x25, 0x7f,                    //   Logical Maximum (127)             83108 * # 0x75, 0x08,                    //   Report Size (8)                   85109 * # 0x95, 0x02,                    //   Report Count (2)                  87110 * # 0x81, 0x02,                    //   Input (Data,Var,Abs)              89111 * # 0xc0,                          //  End Collection                     91112 * # 0xc0,                          // End Collection                      92113 * 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 75 01 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 ff 7f 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 3d 09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0114 *115 * Third hidraw node is the pad which sends a combination of keyboard shortcuts until116 * the tablet is switched to raw mode, then it's mute:117 *118 * # Report descriptor length: 148 bytes119 * # HUION Huion Tablet_Q630M120 * # 0x05, 0x01,                    // Usage Page (Generic Desktop)        0121 * # 0x09, 0x0e,                    // Usage (System Multi-Axis Controller) 2122 * # 0xa1, 0x01,                    // Collection (Application)            4123 * # 0x85, 0x11,                    //  Report ID (17)                     6124 * # 0x05, 0x0d,                    //  Usage Page (Digitizers)            8125 * # 0x09, 0x21,                    //  Usage (Puck)                       10126 * # 0xa1, 0x02,                    //  Collection (Logical)               12127 * # 0x15, 0x00,                    //   Logical Minimum (0)               14128 * # 0x25, 0x01,                    //   Logical Maximum (1)               16129 * # 0x75, 0x01,                    //   Report Size (1)                   18130 * # 0x95, 0x01,                    //   Report Count (1)                  20131 * # 0xa1, 0x00,                    //   Collection (Physical)             22132 * # 0x05, 0x09,                    //    Usage Page (Button)              24133 * # 0x09, 0x01,                    //    Usage (Vendor Usage 0x01)        26134 * # 0x81, 0x02,                    //    Input (Data,Var,Abs)             28135 * # 0x05, 0x0d,                    //    Usage Page (Digitizers)          30136 * # 0x09, 0x33,                    //    Usage (Touch)                    32137 * # 0x81, 0x02,                    //    Input (Data,Var,Abs)             34138 * # 0x95, 0x06,                    //    Report Count (6)                 36139 * # 0x81, 0x03,                    //    Input (Cnst,Var,Abs)             38140 * # 0xa1, 0x02,                    //    Collection (Logical)             40141 * # 0x05, 0x01,                    //     Usage Page (Generic Desktop)    42142 * # 0x09, 0x37,                    //     Usage (Dial)                    44143 * # 0x16, 0x00, 0x80,              //     Logical Minimum (-32768)        46144 * # 0x26, 0xff, 0x7f,              //     Logical Maximum (32767)         49145 * # 0x75, 0x10,                    //     Report Size (16)                52146 * # 0x95, 0x01,                    //     Report Count (1)                54147 * # 0x81, 0x06,                    //     Input (Data,Var,Rel)            56148 * # 0x35, 0x00,                    //     Physical Minimum (0)            58149 * # 0x46, 0x10, 0x0e,              //     Physical Maximum (3600)         60150 * # 0x15, 0x00,                    //     Logical Minimum (0)             63151 * # 0x26, 0x10, 0x0e,              //     Logical Maximum (3600)          65152 * # 0x09, 0x48,                    //     Usage (Resolution Multiplier)   68153 * # 0xb1, 0x02,                    //     Feature (Data,Var,Abs)          70154 * # 0x45, 0x00,                    //     Physical Maximum (0)            72155 * # 0xc0,                          //    End Collection                   74156 * # 0x75, 0x08,                    //    Report Size (8)                  75157 * # 0x95, 0x01,                    //    Report Count (1)                 77158 * # 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             79159 * # 0x75, 0x08,                    //    Report Size (8)                  81160 * # 0x95, 0x01,                    //    Report Count (1)                 83161 * # 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             85162 * # 0x75, 0x08,                    //    Report Size (8)                  87163 * # 0x95, 0x01,                    //    Report Count (1)                 89164 * # 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             91165 * # 0x75, 0x08,                    //    Report Size (8)                  93166 * # 0x95, 0x01,                    //    Report Count (1)                 95167 * # 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             97168 * # 0x75, 0x08,                    //    Report Size (8)                  99169 * # 0x95, 0x01,                    //    Report Count (1)                 101170 * # 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             103171 * # 0xc0,                          //   End Collection                    105172 * # 0xc0,                          //  End Collection                     106173 * # 0xc0,                          // End Collection                      107174 * # 0x05, 0x01,                    // Usage Page (Generic Desktop)        108175 * # 0x09, 0x06,                    // Usage (Keyboard)                    110176 * # 0xa1, 0x01,                    // Collection (Application)            112177 * # 0x85, 0x03,                    //  Report ID (3)                      114178 * # 0x05, 0x07,                    //  Usage Page (Keyboard)              116179 * # 0x19, 0xe0,                    //  Usage Minimum (224)                118180 * # 0x29, 0xe7,                    //  Usage Maximum (231)                120181 * # 0x15, 0x00,                    //  Logical Minimum (0)                122182 * # 0x25, 0x01,                    //  Logical Maximum (1)                124183 * # 0x75, 0x01,                    //  Report Size (1)                    126184 * # 0x95, 0x08,                    //  Report Count (8)                   128185 * # 0x81, 0x02,                    //  Input (Data,Var,Abs)               130186 * # 0x05, 0x07,                    //  Usage Page (Keyboard)              132187 * # 0x19, 0x00,                    //  Usage Minimum (0)                  134188 * # 0x29, 0xff,                    //  Usage Maximum (255)                136189 * # 0x26, 0xff, 0x00,              //  Logical Maximum (255)              138190 * # 0x75, 0x08,                    //  Report Size (8)                    141191 * # 0x95, 0x06,                    //  Report Count (6)                   143192 * # 0x81, 0x00,                    //  Input (Data,Arr,Abs)               145193 * # 0xc0,                          // End Collection                      147194 * R: 148 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0195 */196 197#define PAD_REPORT_DESCRIPTOR_LENGTH 148198#define PEN_REPORT_DESCRIPTOR_LENGTH 93199#define VENDOR_REPORT_DESCRIPTOR_LENGTH 18200#define PAD_REPORT_ID 3201#define DIAL_REPORT_ID 17202#define PEN_REPORT_ID 10203#define VENDOR_REPORT_ID 8204#define PAD_REPORT_LENGTH 9205#define PEN_REPORT_LENGTH 10206#define VENDOR_REPORT_LENGTH 12207 208 209__u8 last_button_state;210 211static const __u8 fixed_rdesc_pad[] = {212	UsagePage_GenericDesktop213	Usage_GD_Keypad214	CollectionApplication(215		// -- Byte 0 in report216		ReportId(PAD_REPORT_ID)217		LogicalRange_i8(0, 1)218		UsagePage_Digitizers219		Usage_Dig_TabletFunctionKeys220		CollectionPhysical(221			// Byte 1 in report - just exists so we get to be a tablet pad222			Usage_Dig_BarrelSwitch // BTN_STYLUS223			ReportCount(1)224			ReportSize(1)225			Input(Var|Abs)226			ReportCount(7) // padding227			Input(Const)228			// Bytes 2/3 in report - just exists so we get to be a tablet pad229			UsagePage_GenericDesktop230			Usage_GD_X231			Usage_GD_Y232			ReportCount(2)233			ReportSize(8)234			Input(Var|Abs)235			// Byte 4 in report is the dial236			Usage_GD_Wheel237			LogicalRange_i8(-1, 1)238			ReportCount(1)239			ReportSize(8)240			Input(Var|Rel)241			// Byte 5 is the button state242			UsagePage_Button243			UsageRange_i8(0x01, 0x8)244			LogicalRange_i8(0x0, 0x1)245			ReportCount(7)246			ReportSize(1)247			Input(Var|Abs)248			ReportCount(1) // padding249			Input(Const)250		)251		// Make sure we match our original report length252		FixedSizeVendorReport(PAD_REPORT_LENGTH)253	)254};255 256static const __u8 fixed_rdesc_pen[] = {257	UsagePage_Digitizers258	Usage_Dig_Pen259	CollectionApplication(260		// -- Byte 0 in report261		ReportId(PEN_REPORT_ID)262		Usage_Dig_Pen263		CollectionPhysical(264			// -- Byte 1 in report265			Usage_Dig_TipSwitch266			Usage_Dig_BarrelSwitch267			Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2268			LogicalRange_i8(0, 1)269			ReportSize(1)270			ReportCount(3)271			Input(Var|Abs)272			ReportCount(4)  // Padding273			Input(Const)274			Usage_Dig_InRange275			ReportCount(1)276			Input(Var|Abs)277			ReportSize(16)278			ReportCount(1)279			PushPop(280				UsagePage_GenericDesktop281				Unit(cm)282				UnitExponent(-1)283				PhysicalRange_i16(0, 266)284				LogicalRange_i16(0, 32767)285				Usage_GD_X286				Input(Var|Abs) // Bytes 2+3287				PhysicalRange_i16(0, 166)288				LogicalRange_i16(0, 32767)289				Usage_GD_Y290				Input(Var|Abs) // Bytes 4+5291			)292			UsagePage_Digitizers293			Usage_Dig_TipPressure294			LogicalRange_i16(0, 8191)295			Input(Var|Abs) // Byte 6+7296			ReportSize(8)297			ReportCount(2)298			LogicalRange_i8(-60, 60)299			Usage_Dig_XTilt300			Usage_Dig_YTilt301			Input(Var|Abs) // Byte 8+9302		)303	)304};305 306static const __u8 fixed_rdesc_vendor[] = {307	UsagePage_Digitizers308	Usage_Dig_Pen309	CollectionApplication(310		// Byte 0311		// We leave the pen on the vendor report ID312		ReportId(VENDOR_REPORT_ID)313		Usage_Dig_Pen314		CollectionPhysical(315			// Byte 1 are the buttons316			LogicalRange_i8(0, 1)317			ReportSize(1)318			Usage_Dig_TipSwitch319			Usage_Dig_BarrelSwitch320			Usage_Dig_SecondaryBarrelSwitch321			ReportCount(3)322			Input(Var|Abs)323			ReportCount(4) // Padding324			Input(Const)325			Usage_Dig_InRange326			ReportCount(1)327			Input(Var|Abs)328			ReportSize(16)329			ReportCount(1)330			PushPop(331				UsagePage_GenericDesktop332				Unit(cm)333				UnitExponent(-1)334				// Note: reported logical range differs335				// from the pen report ID for x and y336				LogicalRange_i16(0, 53340)337				PhysicalRange_i16(0, 266)338				// Bytes 2/3 in report339				Usage_GD_X340				Input(Var|Abs)341				LogicalRange_i16(0, 33340)342				PhysicalRange_i16(0, 166)343				// Bytes 4/5 in report344				Usage_GD_Y345				Input(Var|Abs)346			)347			// Bytes 6/7 in report348			LogicalRange_i16(0, 8191)349			Usage_Dig_TipPressure350			Input(Var|Abs)351			// Bytes 8/9 in report352			ReportCount(1) // Padding353			Input(Const)354			LogicalRange_i8(-60, 60)355			// Byte 10 in report356			Usage_Dig_XTilt357			// Byte 11 in report358			Usage_Dig_YTilt359			ReportSize(8)360			ReportCount(2)361			Input(Var|Abs)362		)363	)364	UsagePage_GenericDesktop365	Usage_GD_Keypad366	CollectionApplication(367		// Byte 0368		ReportId(PAD_REPORT_ID)369		LogicalRange_i8(0, 1)370		UsagePage_Digitizers371		Usage_Dig_TabletFunctionKeys372		CollectionPhysical(373			// Byte 1 are the buttons374			Usage_Dig_BarrelSwitch	 // BTN_STYLUS, needed so we get to be a tablet pad375			ReportCount(1)376			ReportSize(1)377			Input(Var|Abs)378			ReportCount(7) // Padding379			Input(Const)380			// Bytes 2/3 - x/y just exist so we get to be a tablet pad381			UsagePage_GenericDesktop382			Usage_GD_X383			Usage_GD_Y384			ReportCount(2)385			ReportSize(8)386			Input(Var|Abs)387			// Byte 4 is the button state388			UsagePage_Button389			UsageRange_i8(0x01, 0x8)390			LogicalRange_i8(0x0, 0x1)391			ReportCount(8)392			ReportSize(1)393			Input(Var|Abs)394			// Byte 5 is the top dial395			UsagePage_GenericDesktop396			Usage_GD_Wheel397			LogicalRange_i8(-1, 1)398			ReportCount(1)399			ReportSize(8)400			Input(Var|Rel)401			// Byte 6 is the bottom dial402			UsagePage_Consumer403			Usage_Con_ACPan404			Input(Var|Rel)405		)406		// Make sure we match our original report length407		FixedSizeVendorReport(VENDOR_REPORT_LENGTH)408	)409};410 411static const __u8 disabled_rdesc_pen[] = {412	FixedSizeVendorReport(PEN_REPORT_LENGTH)413};414 415static const __u8 disabled_rdesc_pad[] = {416	FixedSizeVendorReport(PAD_REPORT_LENGTH)417};418 419SEC(HID_BPF_RDESC_FIXUP)420int BPF_PROG(dial_2_fix_rdesc, struct hid_bpf_ctx *hctx)421{422	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);423	__s32 rdesc_size = hctx->size;424	__u8 have_fw_id;425 426	if (!data)427		return 0; /* EPERM check */428 429	/* If we have a firmware ID and it matches our expected prefix, we430	 * disable the default pad/pen nodes. They won't send events431	 * but cause duplicate devices.432	 */433	have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,434				      EXPECTED_FIRMWARE_ID,435				      sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;436	if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {437		if (have_fw_id) {438			__builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));439			return sizeof(disabled_rdesc_pad);440		}441 442		__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));443		return sizeof(fixed_rdesc_pad);444	}445	if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {446		if (have_fw_id) {447			__builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));448			return sizeof(disabled_rdesc_pen);449		}450 451		__builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));452		return sizeof(fixed_rdesc_pen);453	}454	/* Always fix the vendor mode so the tablet will work even if nothing sets455	 * the udev property (e.g. huion-switcher run manually)456	 */457	if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {458		__builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));459		return sizeof(fixed_rdesc_vendor);460 461	}462	return 0;463}464 465SEC(HID_BPF_DEVICE_EVENT)466int BPF_PROG(dial_2_fix_events, struct hid_bpf_ctx *hctx)467{468	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 16 /* size */);469	static __u8 button;470 471	if (!data)472		return 0; /* EPERM check */473 474	/* Only sent if tablet is in default mode */475	if (data[0] == PAD_REPORT_ID) {476		/* Nicely enough, this device only supports one button down at a time so477		 * the reports are easy to match. Buttons numbered from the top478		 *   Button released: 03 00 00 00 00 00 00 00479		 *   Button 1: 03 00 05 00 00 00 00 00 -> b480		 *   Button 2: 03 00 08 00 00 00 00 00 -> e481		 *   Button 3: 03 00 0c 00 00 00 00 00 -> i482		 *   Button 4: 03 00 e0 16 00 00 00 00 -> Ctrl S483		 *   Button 5: 03 00 2c 00 00 00 00 00 -> space484		 *   Button 6: 03 00 e0 e2 1d 00 00 00 -> Ctrl Alt Z485		 */486		button &= 0xc0;487 488		switch ((data[2] << 16) | (data[3] << 8) | data[4]) {489		case 0x000000:490			break;491		case 0x050000:492			button |= BIT(0);493			break;494		case 0x080000:495			button |= BIT(1);496			break;497		case 0x0c0000:498			button |= BIT(2);499			break;500		case 0xe01600:501			button |= BIT(3);502			break;503		case 0x2c0000:504			button |= BIT(4);505			break;506		case 0xe0e21d:507			button |= BIT(5);508			break;509		}510 511		__u8 report[8] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, 0x00, button};512 513		__builtin_memcpy(data, report, sizeof(report));514		return sizeof(report);515	}516 517	/* Only sent if tablet is in default mode */518	if (data[0] == DIAL_REPORT_ID) {519		/*520		 * In default mode, both dials are merged together:521		 *522		 *   Dial down: 11 00 ff ff 00 00 00 00 00 -> Dial -1523		 *   Dial up:   11 00 01 00 00 00 00 00 00 -> Dial 1524		 */525		__u16 dial = data[3] << 8 | data[2];526 527		button &= 0x3f;528		button |= !!data[1] << 6;529 530		__u8 report[] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, dial, button};531 532		__builtin_memcpy(data, report, sizeof(report));533		return sizeof(report);534	}535 536	/* Nothing to do for the PEN_REPORT_ID, it's already mapped */537 538	/* Only sent if tablet is in raw mode */539	if (data[0] == VENDOR_REPORT_ID) {540		/* Pad reports */541		if (data[1] & 0x20) {542			/* See fixed_rdesc_pad */543			struct pad_report {544				__u8 report_id;545				__u8 btn_stylus;546				__u8 x;547				__u8 y;548				__u8 buttons;549				__u8 dial_1;550				__u8 dial_2;551			} __attribute__((packed)) *pad_report;552			__u8 dial_1 = 0, dial_2 = 0;553 554			/* Dial report */555			if (data[1] == 0xf1) {556				__u8 d = 0;557 558				if (data[5] == 2)559					d = 0xff;560				else561					d = data[5];562 563				if (data[3] == 1)564					dial_1 = d;565				else566					dial_2 = d;567			} else {568				/* data[4] are the buttons, mapped correctly */569				last_button_state = data[4];570				dial_1 = 0; // dial571				dial_2 = 0;572			}573 574			pad_report = (struct pad_report *)data;575 576			pad_report->report_id = PAD_REPORT_ID;577			pad_report->btn_stylus = 0;578			pad_report->x = 0;579			pad_report->y = 0;580			pad_report->buttons = last_button_state;581			pad_report->dial_1 = dial_1;582			pad_report->dial_2 = dial_2;583 584			return sizeof(struct pad_report);585		}586 587		/* Pen reports need nothing done */588	}589 590	return 0;591}592 593HID_BPF_OPS(inspiroy_dial2) = {594	.hid_device_event = (void *)dial_2_fix_events,595	.hid_rdesc_fixup = (void *)dial_2_fix_rdesc,596};597 598SEC("syscall")599int probe(struct hid_bpf_probe_args *ctx)600{601	switch (ctx->rdesc_size) {602	case PAD_REPORT_DESCRIPTOR_LENGTH:603	case PEN_REPORT_DESCRIPTOR_LENGTH:604	case VENDOR_REPORT_DESCRIPTOR_LENGTH:605		ctx->retval = 0;606		break;607	default:608		ctx->retval = -EINVAL;609	}610 611	return 0;612}613 614char _license[] SEC("license") = "GPL";615