xref: /linux/drivers/hid/bpf/progs/Huion__Kamvas16Gen3.bpf.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1*0412be1bSBenjamin Tissoires // SPDX-License-Identifier: GPL-2.0-only
2*0412be1bSBenjamin Tissoires /* Copyright (c) 2025 Nicholas LaPointe
3*0412be1bSBenjamin Tissoires  * Copyright (c) 2025 Higgins Dragon
4*0412be1bSBenjamin Tissoires  */
5*0412be1bSBenjamin Tissoires 
6*0412be1bSBenjamin Tissoires #include "vmlinux.h"
7*0412be1bSBenjamin Tissoires #include "hid_bpf.h"
8*0412be1bSBenjamin Tissoires #include "hid_bpf_helpers.h"
9*0412be1bSBenjamin Tissoires #include "hid_report_helpers.h"
10*0412be1bSBenjamin Tissoires #include <bpf/bpf_tracing.h>
11*0412be1bSBenjamin Tissoires 
12*0412be1bSBenjamin Tissoires #define VID_HUION 0x256c
13*0412be1bSBenjamin Tissoires #define PID_KAMVAS16_GEN3 0x2009
14*0412be1bSBenjamin Tissoires 
15*0412be1bSBenjamin Tissoires #define VENDOR_DESCRIPTOR_LENGTH 36
16*0412be1bSBenjamin Tissoires #define TABLET_DESCRIPTOR_LENGTH 328
17*0412be1bSBenjamin Tissoires #define WHEEL_DESCRIPTOR_LENGTH 200
18*0412be1bSBenjamin Tissoires 
19*0412be1bSBenjamin Tissoires #define VENDOR_REPORT_ID 8
20*0412be1bSBenjamin Tissoires #define VENDOR_REPORT_LENGTH 14
21*0412be1bSBenjamin Tissoires 
22*0412be1bSBenjamin Tissoires #define VENDOR_REPORT_SUBTYPE_PEN 0x08
23*0412be1bSBenjamin Tissoires #define VENDOR_REPORT_SUBTYPE_PEN_OUT 0x00
24*0412be1bSBenjamin Tissoires #define VENDOR_REPORT_SUBTYPE_BUTTONS 0x0e
25*0412be1bSBenjamin Tissoires #define VENDOR_REPORT_SUBTYPE_WHEELS 0x0f
26*0412be1bSBenjamin Tissoires 
27*0412be1bSBenjamin Tissoires /* For the reports that we create ourselves */
28*0412be1bSBenjamin Tissoires #define CUSTOM_PAD_REPORT_ID 9
29*0412be1bSBenjamin Tissoires 
30*0412be1bSBenjamin Tissoires HID_BPF_CONFIG(
31*0412be1bSBenjamin Tissoires 	HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_HUION, PID_KAMVAS16_GEN3),
32*0412be1bSBenjamin Tissoires );
33*0412be1bSBenjamin Tissoires 
34*0412be1bSBenjamin Tissoires /*
35*0412be1bSBenjamin Tissoires  * This tablet can send reports using one of two different data formats,
36*0412be1bSBenjamin Tissoires  * depending on what "mode" the tablet is in.
37*0412be1bSBenjamin Tissoires  *
38*0412be1bSBenjamin Tissoires  * By default, the tablet will send reports that can be decoded using its
39*0412be1bSBenjamin Tissoires  * included HID descriptors (descriptors 1 and 2, shown below).
40*0412be1bSBenjamin Tissoires  * This mode will be called "firmware mode" throughout this file.
41*0412be1bSBenjamin Tissoires  *
42*0412be1bSBenjamin Tissoires  * The HID descriptor that describes pen events in firmware mode (descriptor 1)
43*0412be1bSBenjamin Tissoires  * has multiple bugs:
44*0412be1bSBenjamin Tissoires  *	* "Secondary Tip Switch" instead of "Secondary Barrel Switch"
45*0412be1bSBenjamin Tissoires  *	* "Invert" instead of (or potentially shared with) third barrel button
46*0412be1bSBenjamin Tissoires  *	* Specified tablet area of 2048 in³ instead of 293.8 x 165.2mm
47*0412be1bSBenjamin Tissoires  *	* Specified tilt range of -90 to +90 instead of -60 to +60
48*0412be1bSBenjamin Tissoires  *
49*0412be1bSBenjamin Tissoires  * While these can be easily patched up by editing the descriptor, a larger
50*0412be1bSBenjamin Tissoires  * problem with the firmware mode exists: it is impossible to tell which of the
51*0412be1bSBenjamin Tissoires  * two wheels are being rotated (or having their central button pressed).
52*0412be1bSBenjamin Tissoires  *
53*0412be1bSBenjamin Tissoires  *
54*0412be1bSBenjamin Tissoires  * By using a tool such as huion-switcher (https://github.com/whot/huion-switcher),
55*0412be1bSBenjamin Tissoires  * the tablet can be made to send reports using a proprietary format that is not
56*0412be1bSBenjamin Tissoires  * adequately described by its relevant descriptor (descriptor 0, shown below).
57*0412be1bSBenjamin Tissoires  * This mode will be called "vendor mode" throughout this file.
58*0412be1bSBenjamin Tissoires  *
59*0412be1bSBenjamin Tissoires  * The reports sent while in vendor mode allow for proper decoding of the wheels.
60*0412be1bSBenjamin Tissoires  *
61*0412be1bSBenjamin Tissoires  * For simplicity and maximum functionality, this BPF focuses strictly on
62*0412be1bSBenjamin Tissoires  * enabling one to make use of the vendor mode.
63*0412be1bSBenjamin Tissoires  */
64*0412be1bSBenjamin Tissoires 
65*0412be1bSBenjamin Tissoires /*
66*0412be1bSBenjamin Tissoires  * DESCRIPTORS
67*0412be1bSBenjamin Tissoires  *	DESCRIPTOR 0
68*0412be1bSBenjamin Tissoires  *		# 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 1)  0
69*0412be1bSBenjamin Tissoires  *		# 0x09, 0x01,                    // Usage (Vendor Usage 1)              3
70*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            5
71*0412be1bSBenjamin Tissoires  *		# 0x85, 0x08,                    //  Report ID (8)                      7
72*0412be1bSBenjamin Tissoires  *		# 0x75, 0x68,                    //  Report Size (104)                  9
73*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //  Report Count (1)                   11
74*0412be1bSBenjamin Tissoires  *		# 0x09, 0x01,                    //  Usage (Vendor Usage 1)             13
75*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //  Input (Data,Var,Abs)               15
76*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      17
77*0412be1bSBenjamin Tissoires  *		# 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 1)  18
78*0412be1bSBenjamin Tissoires  *		# 0x09, 0x01,                    // Usage (Vendor Usage 1)              21
79*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            23
80*0412be1bSBenjamin Tissoires  *		# 0x85, 0x16,                    //  Report ID (22)                     25
81*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //  Report Size (8)                    27
82*0412be1bSBenjamin Tissoires  *		# 0x95, 0x07,                    //  Report Count (7)                   29
83*0412be1bSBenjamin Tissoires  *		# 0x09, 0x01,                    //  Usage (Vendor Usage 1)             31
84*0412be1bSBenjamin Tissoires  *		# 0xb1, 0x02,                    //  Feature (Data,Var,Abs)             33
85*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      35
86*0412be1bSBenjamin Tissoires  *		#
87*0412be1bSBenjamin Tissoires  *		R: 36 06 00 ff 09 01 a1 01 85 08 75 68 95 01 09 01 81 02 c0 06 00 ff 09 01 a1 01 85 16 75 08 95 07 09 01 b1 02 c0
88*0412be1bSBenjamin Tissoires  *		N: HUION Huion Tablet_GS1563
89*0412be1bSBenjamin Tissoires  *		I: 3 256c 2009
90*0412be1bSBenjamin Tissoires  *
91*0412be1bSBenjamin Tissoires  *
92*0412be1bSBenjamin Tissoires  *	DESCRIPTOR 1
93*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    // Usage Page (Digitizers)             0
94*0412be1bSBenjamin Tissoires  *		# 0x09, 0x02,                    // Usage (Pen)                         2
95*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            4
96*0412be1bSBenjamin Tissoires  *		# 0x85, 0x0a,                    //  Report ID (10)                     6
97*0412be1bSBenjamin Tissoires  *		# 0x09, 0x20,                    //  Usage (Stylus)                     8
98*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    //  Collection (Application)           10
99*0412be1bSBenjamin Tissoires  *		# 0x09, 0x42,                    //   Usage (Tip Switch)                12
100*0412be1bSBenjamin Tissoires  *		# 0x09, 0x44,                    //   Usage (Barrel Switch)             14
101*0412be1bSBenjamin Tissoires  *		# 0x09, 0x43,                    //   Usage (Secondary Tip Switch)      16
102*0412be1bSBenjamin Tissoires  *		# 0x09, 0x3c,                    //   Usage (Invert)                    18
103*0412be1bSBenjamin Tissoires  *		# 0x09, 0x45,                    //   Usage (Eraser)                    20
104*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //   Logical Minimum (0)               22
105*0412be1bSBenjamin Tissoires  *		# 0x25, 0x01,                    //   Logical Maximum (1)               24
106*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   26
107*0412be1bSBenjamin Tissoires  *		# 0x95, 0x06,                    //   Report Count (6)                  28
108*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              30
109*0412be1bSBenjamin Tissoires  *		# 0x09, 0x32,                    //   Usage (In Range)                  32
110*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   34
111*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  36
112*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              38
113*0412be1bSBenjamin Tissoires  *		# 0x81, 0x03,                    //   Input (Cnst,Var,Abs)              40
114*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    //   Usage Page (Generic Desktop)      42
115*0412be1bSBenjamin Tissoires  *		# 0x09, 0x30,                    //   Usage (X)                         44
116*0412be1bSBenjamin Tissoires  *		# 0x09, 0x31,                    //   Usage (Y)                         46
117*0412be1bSBenjamin Tissoires  *		# 0x55, 0x0d,                    //   Unit Exponent (-3)                48
118*0412be1bSBenjamin Tissoires  *		# 0x65, 0x33,                    //   Unit (EnglishLinear: in³)         50
119*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           52
120*0412be1bSBenjamin Tissoires  *		# 0x35, 0x00,                    //   Physical Minimum (0)              55
121*0412be1bSBenjamin Tissoires  *		# 0x46, 0x00, 0x08,              //   Physical Maximum (2048)           57
122*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //   Report Size (16)                  60
123*0412be1bSBenjamin Tissoires  *		# 0x95, 0x02,                    //   Report Count (2)                  62
124*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              64
125*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //   Usage Page (Digitizers)           66
126*0412be1bSBenjamin Tissoires  *		# 0x09, 0x30,                    //   Usage (Tip Pressure)              68
127*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x3f,              //   Logical Maximum (16383)           70
128*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //   Report Size (16)                  73
129*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  75
130*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              77
131*0412be1bSBenjamin Tissoires  *		# 0x09, 0x3d,                    //   Usage (X Tilt)                    79
132*0412be1bSBenjamin Tissoires  *		# 0x09, 0x3e,                    //   Usage (Y Tilt)                    81
133*0412be1bSBenjamin Tissoires  *		# 0x15, 0xa6,                    //   Logical Minimum (-90)             83
134*0412be1bSBenjamin Tissoires  *		# 0x25, 0x5a,                    //   Logical Maximum (90)              85
135*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //   Report Size (8)                   87
136*0412be1bSBenjamin Tissoires  *		# 0x95, 0x02,                    //   Report Count (2)                  89
137*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              91
138*0412be1bSBenjamin Tissoires  *		# 0xc0,                          //  End Collection                     93
139*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      94
140*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    // Usage Page (Digitizers)             95
141*0412be1bSBenjamin Tissoires  *		# 0x09, 0x04,                    // Usage (Touch Screen)                97
142*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            99
143*0412be1bSBenjamin Tissoires  *		# 0x85, 0x04,                    //  Report ID (4)                      101
144*0412be1bSBenjamin Tissoires  *		# 0x09, 0x22,                    //  Usage (Finger)                     103
145*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x02,                    //  Collection (Logical)               105
146*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //   Usage Page (Digitizers)           107
147*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  109
148*0412be1bSBenjamin Tissoires  *		# 0x75, 0x06,                    //   Report Size (6)                   111
149*0412be1bSBenjamin Tissoires  *		# 0x09, 0x51,                    //   Usage (Contact Id)                113
150*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //   Logical Minimum (0)               115
151*0412be1bSBenjamin Tissoires  *		# 0x25, 0x3f,                    //   Logical Maximum (63)              117
152*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              119
153*0412be1bSBenjamin Tissoires  *		# 0x09, 0x42,                    //   Usage (Tip Switch)                121
154*0412be1bSBenjamin Tissoires  *		# 0x25, 0x01,                    //   Logical Maximum (1)               123
155*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   125
156*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  127
157*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              129
158*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   131
159*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  133
160*0412be1bSBenjamin Tissoires  *		# 0x81, 0x03,                    //   Input (Cnst,Var,Abs)              135
161*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    //   Usage Page (Generic Desktop)      137
162*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //   Report Size (16)                  139
163*0412be1bSBenjamin Tissoires  *		# 0x55, 0x0e,                    //   Unit Exponent (-2)                141
164*0412be1bSBenjamin Tissoires  *		# 0x65, 0x11,                    //   Unit (SILinear: cm)               143
165*0412be1bSBenjamin Tissoires  *		# 0x09, 0x30,                    //   Usage (X)                         145
166*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           147
167*0412be1bSBenjamin Tissoires  *		# 0x35, 0x00,                    //   Physical Minimum (0)              150
168*0412be1bSBenjamin Tissoires  *		# 0x46, 0x15, 0x0c,              //   Physical Maximum (3093)           152
169*0412be1bSBenjamin Tissoires  *		# 0x81, 0x42,                    //   Input (Data,Var,Abs,Null)         155
170*0412be1bSBenjamin Tissoires  *		# 0x09, 0x31,                    //   Usage (Y)                         157
171*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           159
172*0412be1bSBenjamin Tissoires  *		# 0x46, 0xcb, 0x06,              //   Physical Maximum (1739)           162
173*0412be1bSBenjamin Tissoires  *		# 0x81, 0x42,                    //   Input (Data,Var,Abs,Null)         165
174*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //   Usage Page (Digitizers)           167
175*0412be1bSBenjamin Tissoires  *		# 0x09, 0x30,                    //   Usage (Tip Pressure)              169
176*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x1f,              //   Logical Maximum (8191)            171
177*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //   Report Size (16)                  174
178*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  176
179*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              178
180*0412be1bSBenjamin Tissoires  *		# 0xc0,                          //  End Collection                     180
181*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //  Usage Page (Digitizers)            181
182*0412be1bSBenjamin Tissoires  *		# 0x09, 0x22,                    //  Usage (Finger)                     183
183*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x02,                    //  Collection (Logical)               185
184*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //   Usage Page (Digitizers)           187
185*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  189
186*0412be1bSBenjamin Tissoires  *		# 0x75, 0x06,                    //   Report Size (6)                   191
187*0412be1bSBenjamin Tissoires  *		# 0x09, 0x51,                    //   Usage (Contact Id)                193
188*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //   Logical Minimum (0)               195
189*0412be1bSBenjamin Tissoires  *		# 0x25, 0x3f,                    //   Logical Maximum (63)              197
190*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              199
191*0412be1bSBenjamin Tissoires  *		# 0x09, 0x42,                    //   Usage (Tip Switch)                201
192*0412be1bSBenjamin Tissoires  *		# 0x25, 0x01,                    //   Logical Maximum (1)               203
193*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   205
194*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  207
195*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              209
196*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   211
197*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  213
198*0412be1bSBenjamin Tissoires  *		# 0x81, 0x03,                    //   Input (Cnst,Var,Abs)              215
199*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    //   Usage Page (Generic Desktop)      217
200*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //   Report Size (16)                  219
201*0412be1bSBenjamin Tissoires  *		# 0x55, 0x0e,                    //   Unit Exponent (-2)                221
202*0412be1bSBenjamin Tissoires  *		# 0x65, 0x11,                    //   Unit (SILinear: cm)               223
203*0412be1bSBenjamin Tissoires  *		# 0x09, 0x30,                    //   Usage (X)                         225
204*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           227
205*0412be1bSBenjamin Tissoires  *		# 0x35, 0x00,                    //   Physical Minimum (0)              230
206*0412be1bSBenjamin Tissoires  *		# 0x46, 0x15, 0x0c,              //   Physical Maximum (3093)           232
207*0412be1bSBenjamin Tissoires  *		# 0x81, 0x42,                    //   Input (Data,Var,Abs,Null)         235
208*0412be1bSBenjamin Tissoires  *		# 0x09, 0x31,                    //   Usage (Y)                         237
209*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           239
210*0412be1bSBenjamin Tissoires  *		# 0x46, 0xcb, 0x06,              //   Physical Maximum (1739)           242
211*0412be1bSBenjamin Tissoires  *		# 0x81, 0x42,                    //   Input (Data,Var,Abs,Null)         245
212*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //   Usage Page (Digitizers)           247
213*0412be1bSBenjamin Tissoires  *		# 0x09, 0x30,                    //   Usage (Tip Pressure)              249
214*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x1f,              //   Logical Maximum (8191)            251
215*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //   Report Size (16)                  254
216*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  256
217*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //   Input (Data,Var,Abs)              258
218*0412be1bSBenjamin Tissoires  *		# 0xc0,                          //  End Collection                     260
219*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //  Usage Page (Digitizers)            261
220*0412be1bSBenjamin Tissoires  *		# 0x09, 0x56,                    //  Usage (Scan Time)                  263
221*0412be1bSBenjamin Tissoires  *		# 0x55, 0x00,                    //  Unit Exponent (0)                  265
222*0412be1bSBenjamin Tissoires  *		# 0x65, 0x00,                    //  Unit (None)                        267
223*0412be1bSBenjamin Tissoires  *		# 0x27, 0xff, 0xff, 0xff, 0x7f,  //  Logical Maximum (2147483647)       269
224*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //  Report Count (1)                   274
225*0412be1bSBenjamin Tissoires  *		# 0x75, 0x20,                    //  Report Size (32)                   276
226*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //  Input (Data,Var,Abs)               278
227*0412be1bSBenjamin Tissoires  *		# 0x09, 0x54,                    //  Usage (Contact Count)              280
228*0412be1bSBenjamin Tissoires  *		# 0x25, 0x7f,                    //  Logical Maximum (127)              282
229*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //  Report Count (1)                   284
230*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //  Report Size (8)                    286
231*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //  Input (Data,Var,Abs)               288
232*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //  Report Size (8)                    290
233*0412be1bSBenjamin Tissoires  *		# 0x95, 0x08,                    //  Report Count (8)                   292
234*0412be1bSBenjamin Tissoires  *		# 0x81, 0x03,                    //  Input (Cnst,Var,Abs)               294
235*0412be1bSBenjamin Tissoires  *		# 0x85, 0x05,                    //  Report ID (5)                      296
236*0412be1bSBenjamin Tissoires  *		# 0x09, 0x55,                    //  Usage (Contact Max)                298
237*0412be1bSBenjamin Tissoires  *		# 0x25, 0x0a,                    //  Logical Maximum (10)               300
238*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //  Report Size (8)                    302
239*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //  Report Count (1)                   304
240*0412be1bSBenjamin Tissoires  *		# 0xb1, 0x02,                    //  Feature (Data,Var,Abs)             306
241*0412be1bSBenjamin Tissoires  *		# 0x06, 0x00, 0xff,              //  Usage Page (Vendor Defined Page 1) 308
242*0412be1bSBenjamin Tissoires  *		# 0x09, 0xc5,                    //  Usage (Vendor Usage 0xc5)          311
243*0412be1bSBenjamin Tissoires  *		# 0x85, 0x06,                    //  Report ID (6)                      313
244*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //  Logical Minimum (0)                315
245*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              317
246*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //  Report Size (8)                    320
247*0412be1bSBenjamin Tissoires  *		# 0x96, 0x00, 0x01,              //  Report Count (256)                 322
248*0412be1bSBenjamin Tissoires  *		# 0xb1, 0x02,                    //  Feature (Data,Var,Abs)             325
249*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      327
250*0412be1bSBenjamin Tissoires  *		#
251*0412be1bSBenjamin Tissoires  *		R: 328 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 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 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0
252*0412be1bSBenjamin Tissoires  *		N: HUION Huion Tablet_GS1563
253*0412be1bSBenjamin Tissoires  *		I: 3 256c 2009
254*0412be1bSBenjamin Tissoires  *
255*0412be1bSBenjamin Tissoires  *	DESCRIPTOR 2
256*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    // Usage Page (Generic Desktop)        0
257*0412be1bSBenjamin Tissoires  *		# 0x09, 0x0e,                    // Usage (System Multi-Axis Controller) 2
258*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            4
259*0412be1bSBenjamin Tissoires  *		# 0x85, 0x11,                    //  Report ID (17)                     6
260*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //  Usage Page (Digitizers)            8
261*0412be1bSBenjamin Tissoires  *		# 0x09, 0x21,                    //  Usage (Puck)                       10
262*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x02,                    //  Collection (Logical)               12
263*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //   Logical Minimum (0)               14
264*0412be1bSBenjamin Tissoires  *		# 0x25, 0x01,                    //   Logical Maximum (1)               16
265*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //   Report Size (1)                   18
266*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //   Report Count (1)                  20
267*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x00,                    //   Collection (Physical)             22
268*0412be1bSBenjamin Tissoires  *		# 0x05, 0x09,                    //    Usage Page (Button)              24
269*0412be1bSBenjamin Tissoires  *		# 0x09, 0x01,                    //    Usage (Vendor Usage 0x01)        26
270*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //    Input (Data,Var,Abs)             28
271*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0d,                    //    Usage Page (Digitizers)          30
272*0412be1bSBenjamin Tissoires  *		# 0x09, 0x33,                    //    Usage (Touch)                    32
273*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //    Input (Data,Var,Abs)             34
274*0412be1bSBenjamin Tissoires  *		# 0x95, 0x06,                    //    Report Count (6)                 36
275*0412be1bSBenjamin Tissoires  *		# 0x81, 0x03,                    //    Input (Cnst,Var,Abs)             38
276*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x02,                    //    Collection (Logical)             40
277*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    //     Usage Page (Generic Desktop)    42
278*0412be1bSBenjamin Tissoires  *		# 0x09, 0x37,                    //     Usage (Dial)                    44
279*0412be1bSBenjamin Tissoires  *		# 0x16, 0x00, 0x80,              //     Logical Minimum (-32768)        46
280*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x7f,              //     Logical Maximum (32767)         49
281*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //     Report Size (16)                52
282*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //     Report Count (1)                54
283*0412be1bSBenjamin Tissoires  *		# 0x81, 0x06,                    //     Input (Data,Var,Rel)            56
284*0412be1bSBenjamin Tissoires  *		# 0x35, 0x00,                    //     Physical Minimum (0)            58
285*0412be1bSBenjamin Tissoires  *		# 0x46, 0x10, 0x0e,              //     Physical Maximum (3600)         60
286*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //     Logical Minimum (0)             63
287*0412be1bSBenjamin Tissoires  *		# 0x26, 0x10, 0x0e,              //     Logical Maximum (3600)          65
288*0412be1bSBenjamin Tissoires  *		# 0x09, 0x48,                    //     Usage (Resolution Multiplier)   68
289*0412be1bSBenjamin Tissoires  *		# 0xb1, 0x02,                    //     Feature (Data,Var,Abs)          70
290*0412be1bSBenjamin Tissoires  *		# 0x45, 0x00,                    //     Physical Maximum (0)            72
291*0412be1bSBenjamin Tissoires  *		# 0xc0,                          //    End Collection                   74
292*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //    Report Size (8)                  75
293*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //    Report Count (1)                 77
294*0412be1bSBenjamin Tissoires  *		# 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             79
295*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //    Report Size (8)                  81
296*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //    Report Count (1)                 83
297*0412be1bSBenjamin Tissoires  *		# 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             85
298*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //    Report Size (8)                  87
299*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //    Report Count (1)                 89
300*0412be1bSBenjamin Tissoires  *		# 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             91
301*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //    Report Size (8)                  93
302*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //    Report Count (1)                 95
303*0412be1bSBenjamin Tissoires  *		# 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             97
304*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //    Report Size (8)                  99
305*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //    Report Count (1)                 101
306*0412be1bSBenjamin Tissoires  *		# 0x81, 0x01,                    //    Input (Cnst,Arr,Abs)             103
307*0412be1bSBenjamin Tissoires  *		# 0xc0,                          //   End Collection                    105
308*0412be1bSBenjamin Tissoires  *		# 0xc0,                          //  End Collection                     106
309*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      107
310*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    // Usage Page (Generic Desktop)        108
311*0412be1bSBenjamin Tissoires  *		# 0x09, 0x06,                    // Usage (Keyboard)                    110
312*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            112
313*0412be1bSBenjamin Tissoires  *		# 0x85, 0x03,                    //  Report ID (3)                      114
314*0412be1bSBenjamin Tissoires  *		# 0x05, 0x07,                    //  Usage Page (Keyboard)              116
315*0412be1bSBenjamin Tissoires  *		# 0x19, 0xe0,                    //  Usage Minimum (224)                118
316*0412be1bSBenjamin Tissoires  *		# 0x29, 0xe7,                    //  Usage Maximum (231)                120
317*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //  Logical Minimum (0)                122
318*0412be1bSBenjamin Tissoires  *		# 0x25, 0x01,                    //  Logical Maximum (1)                124
319*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //  Report Size (1)                    126
320*0412be1bSBenjamin Tissoires  *		# 0x95, 0x08,                    //  Report Count (8)                   128
321*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //  Input (Data,Var,Abs)               130
322*0412be1bSBenjamin Tissoires  *		# 0x05, 0x07,                    //  Usage Page (Keyboard)              132
323*0412be1bSBenjamin Tissoires  *		# 0x19, 0x00,                    //  Usage Minimum (0)                  134
324*0412be1bSBenjamin Tissoires  *		# 0x29, 0xff,                    //  Usage Maximum (255)                136
325*0412be1bSBenjamin Tissoires  *		# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              138
326*0412be1bSBenjamin Tissoires  *		# 0x75, 0x08,                    //  Report Size (8)                    141
327*0412be1bSBenjamin Tissoires  *		# 0x95, 0x06,                    //  Report Count (6)                   143
328*0412be1bSBenjamin Tissoires  *		# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               145
329*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      147
330*0412be1bSBenjamin Tissoires  *		# 0x05, 0x0c,                    // Usage Page (Consumer Devices)       148
331*0412be1bSBenjamin Tissoires  *		# 0x09, 0x01,                    // Usage (Consumer Control)            150
332*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            152
333*0412be1bSBenjamin Tissoires  *		# 0x85, 0x04,                    //  Report ID (4)                      154
334*0412be1bSBenjamin Tissoires  *		# 0x19, 0x01,                    //  Usage Minimum (1)                  156
335*0412be1bSBenjamin Tissoires  *		# 0x2a, 0x9c, 0x02,              //  Usage Maximum (668)                158
336*0412be1bSBenjamin Tissoires  *		# 0x15, 0x01,                    //  Logical Minimum (1)                161
337*0412be1bSBenjamin Tissoires  *		# 0x26, 0x9c, 0x02,              //  Logical Maximum (668)              163
338*0412be1bSBenjamin Tissoires  *		# 0x95, 0x01,                    //  Report Count (1)                   166
339*0412be1bSBenjamin Tissoires  *		# 0x75, 0x10,                    //  Report Size (16)                   168
340*0412be1bSBenjamin Tissoires  *		# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               170
341*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      172
342*0412be1bSBenjamin Tissoires  *		# 0x05, 0x01,                    // Usage Page (Generic Desktop)        173
343*0412be1bSBenjamin Tissoires  *		# 0x09, 0x80,                    // Usage (System Control)              175
344*0412be1bSBenjamin Tissoires  *		# 0xa1, 0x01,                    // Collection (Application)            177
345*0412be1bSBenjamin Tissoires  *		# 0x85, 0x05,                    //  Report ID (5)                      179
346*0412be1bSBenjamin Tissoires  *		# 0x19, 0x81,                    //  Usage Minimum (129)                181
347*0412be1bSBenjamin Tissoires  *		# 0x29, 0x83,                    //  Usage Maximum (131)                183
348*0412be1bSBenjamin Tissoires  *		# 0x15, 0x00,                    //  Logical Minimum (0)                185
349*0412be1bSBenjamin Tissoires  *		# 0x25, 0x01,                    //  Logical Maximum (1)                187
350*0412be1bSBenjamin Tissoires  *		# 0x75, 0x01,                    //  Report Size (1)                    189
351*0412be1bSBenjamin Tissoires  *		# 0x95, 0x03,                    //  Report Count (3)                   191
352*0412be1bSBenjamin Tissoires  *		# 0x81, 0x02,                    //  Input (Data,Var,Abs)               193
353*0412be1bSBenjamin Tissoires  *		# 0x95, 0x05,                    //  Report Count (5)                   195
354*0412be1bSBenjamin Tissoires  *		# 0x81, 0x01,                    //  Input (Cnst,Arr,Abs)               197
355*0412be1bSBenjamin Tissoires  *		# 0xc0,                          // End Collection                      199
356*0412be1bSBenjamin Tissoires  *		#
357*0412be1bSBenjamin Tissoires  *		R: 200 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 c0 05 0c 09 01 a1 01 85 04 19 01 2a 9c 02 15 01 26 9c 02 95 01 75 10 81 00 c0 05 01 09 80 a1 01 85 05 19 81 29 83 15 00 25 01 75 01 95 03 81 02 95 05 81 01 c0
358*0412be1bSBenjamin Tissoires  *		N: HUION Huion Tablet_GS1563
359*0412be1bSBenjamin Tissoires  *		I: 3 256c 2009
360*0412be1bSBenjamin Tissoires  *
361*0412be1bSBenjamin Tissoires  *
362*0412be1bSBenjamin Tissoires  *
363*0412be1bSBenjamin Tissoires  * VENDOR MODE
364*0412be1bSBenjamin Tissoires  *	HUION_FIRMWARE_ID="HUION_M22d_241101"
365*0412be1bSBenjamin Tissoires  *	HUION_MAGIC_BYTES="1403201101ac9900ff3fd81305080080083c4010"
366*0412be1bSBenjamin Tissoires  *
367*0412be1bSBenjamin Tissoires  *	MAGIC BYTES
368*0412be1bSBenjamin Tissoires  *	          [LogicalMaximum, X   ] [LogicalMaximum, Y   ] [LogicalMaximum, Pressure] [  LPI]
369*0412be1bSBenjamin Tissoires  *	    14 03 [            20 11 01] [            ac 99 00] [                   ff 3f] [d8 13] 05 08 00 80 08 3c 40 10
370*0412be1bSBenjamin Tissoires  *
371*0412be1bSBenjamin Tissoires  * See Huion__Kamvas13Gen3.bpf.c for more details on detailed button/dial reports and caveats. It's very
372*0412be1bSBenjamin Tissoires  * similar to the Kamvas 16 Gen 3.
373*0412be1bSBenjamin Tissoires  */
374*0412be1bSBenjamin Tissoires 
375*0412be1bSBenjamin Tissoires 
376*0412be1bSBenjamin Tissoires /* Filled in by udev-hid-bpf */
377*0412be1bSBenjamin Tissoires char UDEV_PROP_HUION_FIRMWARE_ID[64];
378*0412be1bSBenjamin Tissoires 
379*0412be1bSBenjamin Tissoires char EXPECTED_FIRMWARE_ID[] = "HUION_M22d_";
380*0412be1bSBenjamin Tissoires 
381*0412be1bSBenjamin Tissoires __u8 last_button_state;
382*0412be1bSBenjamin Tissoires 
383*0412be1bSBenjamin Tissoires static const __u8 disabled_rdesc_tablet[] = {
384*0412be1bSBenjamin Tissoires 	FixedSizeVendorReport(28)	/* Input report 4 */
385*0412be1bSBenjamin Tissoires };
386*0412be1bSBenjamin Tissoires 
387*0412be1bSBenjamin Tissoires static const __u8 disabled_rdesc_wheel[] = {
388*0412be1bSBenjamin Tissoires 	FixedSizeVendorReport(9)	/* Input report 17 */
389*0412be1bSBenjamin Tissoires };
390*0412be1bSBenjamin Tissoires 
391*0412be1bSBenjamin Tissoires static const __u8 fixed_rdesc_vendor[] = {
392*0412be1bSBenjamin Tissoires 	UsagePage_Digitizers
393*0412be1bSBenjamin Tissoires 	Usage_Dig_Pen
394*0412be1bSBenjamin Tissoires 	CollectionApplication(
395*0412be1bSBenjamin Tissoires 		ReportId(VENDOR_REPORT_ID)
396*0412be1bSBenjamin Tissoires 		UsagePage_Digitizers
397*0412be1bSBenjamin Tissoires 		Usage_Dig_Pen
398*0412be1bSBenjamin Tissoires 		CollectionPhysical(
399*0412be1bSBenjamin Tissoires 			/*
400*0412be1bSBenjamin Tissoires 			 * I have only examined the tablet's behavior while using
401*0412be1bSBenjamin Tissoires 			 * the PW600L pen, which does not have an eraser.
402*0412be1bSBenjamin Tissoires 			 * Because of this, I don't know where the Eraser and Invert
403*0412be1bSBenjamin Tissoires 			 * bits will go, or if they work as one would expect.
404*0412be1bSBenjamin Tissoires 			 *
405*0412be1bSBenjamin Tissoires 			 * For the time being, there is no expectation that a pen
406*0412be1bSBenjamin Tissoires 			 * with an eraser will work without modifications here.
407*0412be1bSBenjamin Tissoires 			 */
408*0412be1bSBenjamin Tissoires 			ReportSize(1)
409*0412be1bSBenjamin Tissoires 			LogicalMinimum_i8(0)
410*0412be1bSBenjamin Tissoires 			LogicalMaximum_i8(1)
411*0412be1bSBenjamin Tissoires 			ReportCount(3)
412*0412be1bSBenjamin Tissoires 			Usage_Dig_TipSwitch
413*0412be1bSBenjamin Tissoires 			Usage_Dig_BarrelSwitch
414*0412be1bSBenjamin Tissoires 			Usage_Dig_SecondaryBarrelSwitch
415*0412be1bSBenjamin Tissoires 			Input(Var|Abs)
416*0412be1bSBenjamin Tissoires 			PushPop(
417*0412be1bSBenjamin Tissoires 				ReportCount(1)
418*0412be1bSBenjamin Tissoires 				UsagePage_Button
419*0412be1bSBenjamin Tissoires 				Usage_i8(0x4a)	/* (BTN_STYLUS3 + 1) & 0xff */
420*0412be1bSBenjamin Tissoires 				Input(Var|Abs)
421*0412be1bSBenjamin Tissoires 			)
422*0412be1bSBenjamin Tissoires 			ReportCount(3)
423*0412be1bSBenjamin Tissoires 			Input(Const)
424*0412be1bSBenjamin Tissoires 			ReportCount(1)
425*0412be1bSBenjamin Tissoires 			Usage_Dig_InRange
426*0412be1bSBenjamin Tissoires 			Input(Var|Abs)
427*0412be1bSBenjamin Tissoires 			ReportSize(16)
428*0412be1bSBenjamin Tissoires 			ReportCount(1)
429*0412be1bSBenjamin Tissoires 			PushPop(
430*0412be1bSBenjamin Tissoires 				UsagePage_GenericDesktop
431*0412be1bSBenjamin Tissoires 				Unit(cm)
432*0412be1bSBenjamin Tissoires 				UnitExponent(-2)
433*0412be1bSBenjamin Tissoires 				LogicalMinimum_i16(0)
434*0412be1bSBenjamin Tissoires 				PhysicalMinimum_i16(0)
435*0412be1bSBenjamin Tissoires 				/*
436*0412be1bSBenjamin Tissoires 				 * The tablet has a logical maximum of 69920 x 39340
437*0412be1bSBenjamin Tissoires 				 * and a claimed resolution of 5080 LPI (200 L/mm)
438*0412be1bSBenjamin Tissoires 				 * This works out to a physical maximum of
439*0412be1bSBenjamin Tissoires 				 * 349.6 x 196.7mm, which matches Huion's advertised
440*0412be1bSBenjamin Tissoires 				 * (rounded) active area dimensions from
441*0412be1bSBenjamin Tissoires 				 * https://www.huion.com/products/pen_display/Kamvas/kamvas-16-gen-3.html
442*0412be1bSBenjamin Tissoires 				 *
443*0412be1bSBenjamin Tissoires 				 * The Kamvas uses data[8] for the 3rd byte of the X-axis, and adding
444*0412be1bSBenjamin Tissoires 				 * that after data[2] and data[3] makes a contiguous little-endian
445*0412be1bSBenjamin Tissoires 				 * 24-bit value. (See BPF_PROG below)
446*0412be1bSBenjamin Tissoires 				 */
447*0412be1bSBenjamin Tissoires 				ReportSize(24)
448*0412be1bSBenjamin Tissoires 				LogicalMaximum_i32(69920)
449*0412be1bSBenjamin Tissoires 				PhysicalMaximum_i16(3496)
450*0412be1bSBenjamin Tissoires 				Usage_GD_X
451*0412be1bSBenjamin Tissoires 				Input(Var|Abs)
452*0412be1bSBenjamin Tissoires 				ReportSize(16)
453*0412be1bSBenjamin Tissoires 				LogicalMaximum_i16(39340)
454*0412be1bSBenjamin Tissoires 				PhysicalMaximum_i16(1967)
455*0412be1bSBenjamin Tissoires 				Usage_GD_Y
456*0412be1bSBenjamin Tissoires 				Input(Var|Abs)
457*0412be1bSBenjamin Tissoires 			)
458*0412be1bSBenjamin Tissoires 			ReportSize(16)
459*0412be1bSBenjamin Tissoires 			LogicalMinimum_i16(0)
460*0412be1bSBenjamin Tissoires 			LogicalMaximum_i16(16383)
461*0412be1bSBenjamin Tissoires 			Usage_Dig_TipPressure
462*0412be1bSBenjamin Tissoires 			Input(Var|Abs)
463*0412be1bSBenjamin Tissoires 			ReportSize(8)
464*0412be1bSBenjamin Tissoires 			ReportCount(1)
465*0412be1bSBenjamin Tissoires 			Input(Const)
466*0412be1bSBenjamin Tissoires 			ReportCount(2)
467*0412be1bSBenjamin Tissoires 			PushPop(
468*0412be1bSBenjamin Tissoires 				Unit(deg)
469*0412be1bSBenjamin Tissoires 				UnitExponent(0)
470*0412be1bSBenjamin Tissoires 				LogicalMinimum_i8(-60)
471*0412be1bSBenjamin Tissoires 				PhysicalMinimum_i8(-60)
472*0412be1bSBenjamin Tissoires 				LogicalMaximum_i8(60)
473*0412be1bSBenjamin Tissoires 				PhysicalMaximum_i8(60)
474*0412be1bSBenjamin Tissoires 				Usage_Dig_XTilt
475*0412be1bSBenjamin Tissoires 				Usage_Dig_YTilt
476*0412be1bSBenjamin Tissoires 				Input(Var|Abs)
477*0412be1bSBenjamin Tissoires 			)
478*0412be1bSBenjamin Tissoires 		)
479*0412be1bSBenjamin Tissoires 	)
480*0412be1bSBenjamin Tissoires 	UsagePage_GenericDesktop
481*0412be1bSBenjamin Tissoires 	Usage_GD_Keypad
482*0412be1bSBenjamin Tissoires 	CollectionApplication(
483*0412be1bSBenjamin Tissoires 		ReportId(CUSTOM_PAD_REPORT_ID)
484*0412be1bSBenjamin Tissoires 		LogicalMinimum_i8(0)
485*0412be1bSBenjamin Tissoires 		LogicalMaximum_i8(1)
486*0412be1bSBenjamin Tissoires 		UsagePage_Digitizers
487*0412be1bSBenjamin Tissoires 		Usage_Dig_TabletFunctionKeys
488*0412be1bSBenjamin Tissoires 		CollectionPhysical(
489*0412be1bSBenjamin Tissoires 			/*
490*0412be1bSBenjamin Tissoires 			 * The first 3 bytes are somewhat vestigial and will
491*0412be1bSBenjamin Tissoires 			 * always be set to zero. Their presence here is needed
492*0412be1bSBenjamin Tissoires 			 * to ensure that this device will be detected as a
493*0412be1bSBenjamin Tissoires 			 * tablet pad by software that otherwise wouldn't know
494*0412be1bSBenjamin Tissoires 			 * any better.
495*0412be1bSBenjamin Tissoires 			 */
496*0412be1bSBenjamin Tissoires 			/* (data[1] & 0x01)	barrel switch */
497*0412be1bSBenjamin Tissoires 			ReportSize(1)
498*0412be1bSBenjamin Tissoires 			ReportCount(1)
499*0412be1bSBenjamin Tissoires 			Usage_Dig_BarrelSwitch
500*0412be1bSBenjamin Tissoires 			Input(Var|Abs)
501*0412be1bSBenjamin Tissoires 			ReportCount(7)
502*0412be1bSBenjamin Tissoires 			Input(Const)
503*0412be1bSBenjamin Tissoires 			/* data[2]	X */
504*0412be1bSBenjamin Tissoires 			/* data[3]	Y */
505*0412be1bSBenjamin Tissoires 			ReportSize(8)
506*0412be1bSBenjamin Tissoires 			ReportCount(2)
507*0412be1bSBenjamin Tissoires 			UsagePage_GenericDesktop
508*0412be1bSBenjamin Tissoires 			Usage_GD_X
509*0412be1bSBenjamin Tissoires 			Usage_GD_Y
510*0412be1bSBenjamin Tissoires 			Input(Var|Abs)
511*0412be1bSBenjamin Tissoires 			/*
512*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x01)	button 1
513*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x02)	button 2
514*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x04)	button 3
515*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x08)	button 4
516*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x10)	button 5
517*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x20)	button 6
518*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x40)	button 7 (top wheel button)
519*0412be1bSBenjamin Tissoires 			 * (data[4] & 0x80)	button 8 (bottom wheel button)
520*0412be1bSBenjamin Tissoires 			 */
521*0412be1bSBenjamin Tissoires 			ReportSize(1)
522*0412be1bSBenjamin Tissoires 			ReportCount(8)
523*0412be1bSBenjamin Tissoires 			UsagePage_Button
524*0412be1bSBenjamin Tissoires 			UsageMinimum_i8(1)
525*0412be1bSBenjamin Tissoires 			UsageMaximum_i8(8)
526*0412be1bSBenjamin Tissoires 			Input(Var|Abs)
527*0412be1bSBenjamin Tissoires 			/* data[5]	top wheel (signed, positive clockwise) */
528*0412be1bSBenjamin Tissoires 			ReportSize(8)
529*0412be1bSBenjamin Tissoires 			ReportCount(1)
530*0412be1bSBenjamin Tissoires 			UsagePage_GenericDesktop
531*0412be1bSBenjamin Tissoires 			Usage_GD_Wheel
532*0412be1bSBenjamin Tissoires 			LogicalMinimum_i8(-1)
533*0412be1bSBenjamin Tissoires 			LogicalMaximum_i8(1)
534*0412be1bSBenjamin Tissoires 			Input(Var|Rel)
535*0412be1bSBenjamin Tissoires 			/* data[6]	bottom wheel (signed, positive clockwise) */
536*0412be1bSBenjamin Tissoires 			UsagePage_Consumer
537*0412be1bSBenjamin Tissoires 			Usage_Con_ACPan
538*0412be1bSBenjamin Tissoires 			Input(Var|Rel)
539*0412be1bSBenjamin Tissoires 		)
540*0412be1bSBenjamin Tissoires 		/*
541*0412be1bSBenjamin Tissoires 		 * The kernel will drop reports that are bigger than the
542*0412be1bSBenjamin Tissoires 		 * largest report specified in the HID descriptor.
543*0412be1bSBenjamin Tissoires 		 * Therefore, our modified descriptor needs to have at least one
544*0412be1bSBenjamin Tissoires 		 * HID report that is as long as, or longer than, the largest
545*0412be1bSBenjamin Tissoires 		 * report in the original descriptor.
546*0412be1bSBenjamin Tissoires 		 *
547*0412be1bSBenjamin Tissoires 		 * This macro expands to a no-op report that is padded to the
548*0412be1bSBenjamin Tissoires 		 * provided length.
549*0412be1bSBenjamin Tissoires 		 */
550*0412be1bSBenjamin Tissoires 		FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
551*0412be1bSBenjamin Tissoires 	)
552*0412be1bSBenjamin Tissoires };
553*0412be1bSBenjamin Tissoires 
554*0412be1bSBenjamin Tissoires SEC(HID_BPF_RDESC_FIXUP)
555*0412be1bSBenjamin Tissoires int BPF_PROG(hid_fix_rdesc_huion_kamvas16_gen3, struct hid_bpf_ctx *hid_ctx)
556*0412be1bSBenjamin Tissoires {
557*0412be1bSBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
558*0412be1bSBenjamin Tissoires 	__s32 rdesc_size = hid_ctx->size;
559*0412be1bSBenjamin Tissoires 	__u8 have_fw_id;
560*0412be1bSBenjamin Tissoires 
561*0412be1bSBenjamin Tissoires 	if (!data)
562*0412be1bSBenjamin Tissoires 		return 0; /* EPERM check */
563*0412be1bSBenjamin Tissoires 
564*0412be1bSBenjamin Tissoires 	have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
565*0412be1bSBenjamin Tissoires 					EXPECTED_FIRMWARE_ID,
566*0412be1bSBenjamin Tissoires 					sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
567*0412be1bSBenjamin Tissoires 
568*0412be1bSBenjamin Tissoires 	if (have_fw_id) {
569*0412be1bSBenjamin Tissoires 		/*
570*0412be1bSBenjamin Tissoires 		 * Tablet should be in vendor mode.
571*0412be1bSBenjamin Tissoires 		 * Disable the unused devices
572*0412be1bSBenjamin Tissoires 		 */
573*0412be1bSBenjamin Tissoires 		if (rdesc_size == TABLET_DESCRIPTOR_LENGTH) {
574*0412be1bSBenjamin Tissoires 			__builtin_memcpy(data, disabled_rdesc_tablet,
575*0412be1bSBenjamin Tissoires 					 sizeof(disabled_rdesc_tablet));
576*0412be1bSBenjamin Tissoires 			return sizeof(disabled_rdesc_tablet);
577*0412be1bSBenjamin Tissoires 		}
578*0412be1bSBenjamin Tissoires 
579*0412be1bSBenjamin Tissoires 		if (rdesc_size == WHEEL_DESCRIPTOR_LENGTH) {
580*0412be1bSBenjamin Tissoires 			__builtin_memcpy(data, disabled_rdesc_wheel,
581*0412be1bSBenjamin Tissoires 					 sizeof(disabled_rdesc_wheel));
582*0412be1bSBenjamin Tissoires 			return sizeof(disabled_rdesc_wheel);
583*0412be1bSBenjamin Tissoires 		}
584*0412be1bSBenjamin Tissoires 	}
585*0412be1bSBenjamin Tissoires 
586*0412be1bSBenjamin Tissoires 	/*
587*0412be1bSBenjamin Tissoires 	 * Regardless of which mode the tablet is in, always fix the vendor
588*0412be1bSBenjamin Tissoires 	 * descriptor in case the udev property just happened to not be set
589*0412be1bSBenjamin Tissoires 	 */
590*0412be1bSBenjamin Tissoires 	if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) {
591*0412be1bSBenjamin Tissoires 		__builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
592*0412be1bSBenjamin Tissoires 		return sizeof(fixed_rdesc_vendor);
593*0412be1bSBenjamin Tissoires 	}
594*0412be1bSBenjamin Tissoires 
595*0412be1bSBenjamin Tissoires 	return 0;
596*0412be1bSBenjamin Tissoires }
597*0412be1bSBenjamin Tissoires 
598*0412be1bSBenjamin Tissoires SEC(HID_BPF_DEVICE_EVENT)
599*0412be1bSBenjamin Tissoires int BPF_PROG(hid_fix_event_huion_kamvas16_gen3, struct hid_bpf_ctx *hid_ctx)
600*0412be1bSBenjamin Tissoires {
601*0412be1bSBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, VENDOR_REPORT_LENGTH /* size */);
602*0412be1bSBenjamin Tissoires 
603*0412be1bSBenjamin Tissoires 	if (!data)
604*0412be1bSBenjamin Tissoires 		return 0; /* EPERM check */
605*0412be1bSBenjamin Tissoires 
606*0412be1bSBenjamin Tissoires 	/* Handle vendor reports only */
607*0412be1bSBenjamin Tissoires 	if (hid_ctx->size != VENDOR_REPORT_LENGTH)
608*0412be1bSBenjamin Tissoires 		return 0;
609*0412be1bSBenjamin Tissoires 	if (data[0] != VENDOR_REPORT_ID)
610*0412be1bSBenjamin Tissoires 		return 0;
611*0412be1bSBenjamin Tissoires 
612*0412be1bSBenjamin Tissoires 	__u8 report_subtype = (data[1] >> 4) & 0x0f;
613*0412be1bSBenjamin Tissoires 
614*0412be1bSBenjamin Tissoires 	if (report_subtype == VENDOR_REPORT_SUBTYPE_PEN ||
615*0412be1bSBenjamin Tissoires 	    report_subtype == VENDOR_REPORT_SUBTYPE_PEN_OUT) {
616*0412be1bSBenjamin Tissoires 		/* Invert Y tilt */
617*0412be1bSBenjamin Tissoires 		data[11] = -data[11];
618*0412be1bSBenjamin Tissoires 
619*0412be1bSBenjamin Tissoires 		/*
620*0412be1bSBenjamin Tissoires 		 * Rearrange the bytes of the report so that
621*0412be1bSBenjamin Tissoires 		 * [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
622*0412be1bSBenjamin Tissoires 		 * will be arranged as
623*0412be1bSBenjamin Tissoires 		 * [0, 1, 2, 3, 8, 4, 5, 6, 7, 9, 10, 11, 12, 13]
624*0412be1bSBenjamin Tissoires 		 */
625*0412be1bSBenjamin Tissoires 		__u8 x_24 = data[8];
626*0412be1bSBenjamin Tissoires 
627*0412be1bSBenjamin Tissoires 		data[8] = data[7];
628*0412be1bSBenjamin Tissoires 		data[7] = data[6];
629*0412be1bSBenjamin Tissoires 		data[6] = data[5];
630*0412be1bSBenjamin Tissoires 		data[5] = data[4];
631*0412be1bSBenjamin Tissoires 
632*0412be1bSBenjamin Tissoires 		data[4] = x_24;
633*0412be1bSBenjamin Tissoires 
634*0412be1bSBenjamin Tissoires 	} else if (report_subtype == VENDOR_REPORT_SUBTYPE_BUTTONS ||
635*0412be1bSBenjamin Tissoires 		   report_subtype == VENDOR_REPORT_SUBTYPE_WHEELS) {
636*0412be1bSBenjamin Tissoires 		struct pad_report {
637*0412be1bSBenjamin Tissoires 			__u8 report_id;
638*0412be1bSBenjamin Tissoires 			__u8 btn_stylus:1;
639*0412be1bSBenjamin Tissoires 			__u8 padding:7;
640*0412be1bSBenjamin Tissoires 			__u8 x;
641*0412be1bSBenjamin Tissoires 			__u8 y;
642*0412be1bSBenjamin Tissoires 			__u8 buttons;
643*0412be1bSBenjamin Tissoires 			__s8 top_wheel;
644*0412be1bSBenjamin Tissoires 			__s8 bottom_wheel;
645*0412be1bSBenjamin Tissoires 		} __attribute__((packed)) *pad_report;
646*0412be1bSBenjamin Tissoires 
647*0412be1bSBenjamin Tissoires 		__s8 top_wheel = 0;
648*0412be1bSBenjamin Tissoires 		__s8 bottom_wheel = 0;
649*0412be1bSBenjamin Tissoires 
650*0412be1bSBenjamin Tissoires 		switch (report_subtype) {
651*0412be1bSBenjamin Tissoires 		case VENDOR_REPORT_SUBTYPE_WHEELS:
652*0412be1bSBenjamin Tissoires 			/*
653*0412be1bSBenjamin Tissoires 			 * The wheel direction byte is 1 for clockwise rotation
654*0412be1bSBenjamin Tissoires 			 * and 2 for counter-clockwise.
655*0412be1bSBenjamin Tissoires 			 * Change it to 1 and -1, respectively.
656*0412be1bSBenjamin Tissoires 			 */
657*0412be1bSBenjamin Tissoires 			switch (data[3]) {
658*0412be1bSBenjamin Tissoires 			case 1:
659*0412be1bSBenjamin Tissoires 				top_wheel = (data[5] == 1) ? 1 : -1;
660*0412be1bSBenjamin Tissoires 				break;
661*0412be1bSBenjamin Tissoires 			case 2:
662*0412be1bSBenjamin Tissoires 				bottom_wheel = (data[5] == 1) ? 1 : -1;
663*0412be1bSBenjamin Tissoires 				break;
664*0412be1bSBenjamin Tissoires 			}
665*0412be1bSBenjamin Tissoires 			break;
666*0412be1bSBenjamin Tissoires 
667*0412be1bSBenjamin Tissoires 		case VENDOR_REPORT_SUBTYPE_BUTTONS:
668*0412be1bSBenjamin Tissoires 			/*
669*0412be1bSBenjamin Tissoires 			 * If a button is already being held, ignore any new
670*0412be1bSBenjamin Tissoires 			 * button event unless it's a release.
671*0412be1bSBenjamin Tissoires 			 *
672*0412be1bSBenjamin Tissoires 			 * The tablet only cleanly handles one button being held
673*0412be1bSBenjamin Tissoires 			 * at a time, and trying to hold multiple buttons
674*0412be1bSBenjamin Tissoires 			 * (particularly wheel+pad buttons) can result in sequences
675*0412be1bSBenjamin Tissoires 			 * of reports that look like imaginary presses and releases.
676*0412be1bSBenjamin Tissoires 			 *
677*0412be1bSBenjamin Tissoires 			 * This is an imperfect way to filter out some of these
678*0412be1bSBenjamin Tissoires 			 * reports.
679*0412be1bSBenjamin Tissoires 			 */
680*0412be1bSBenjamin Tissoires 			if (last_button_state != 0x00 && data[4] != 0x00)
681*0412be1bSBenjamin Tissoires 				break;
682*0412be1bSBenjamin Tissoires 
683*0412be1bSBenjamin Tissoires 			last_button_state = data[4];
684*0412be1bSBenjamin Tissoires 			break;
685*0412be1bSBenjamin Tissoires 		}
686*0412be1bSBenjamin Tissoires 
687*0412be1bSBenjamin Tissoires 		pad_report = (struct pad_report *)data;
688*0412be1bSBenjamin Tissoires 
689*0412be1bSBenjamin Tissoires 		pad_report->report_id = CUSTOM_PAD_REPORT_ID;
690*0412be1bSBenjamin Tissoires 		pad_report->btn_stylus = 0;
691*0412be1bSBenjamin Tissoires 		pad_report->x = 0;
692*0412be1bSBenjamin Tissoires 		pad_report->y = 0;
693*0412be1bSBenjamin Tissoires 		pad_report->buttons = last_button_state;
694*0412be1bSBenjamin Tissoires 		pad_report->top_wheel = top_wheel;
695*0412be1bSBenjamin Tissoires 		pad_report->bottom_wheel = bottom_wheel;
696*0412be1bSBenjamin Tissoires 
697*0412be1bSBenjamin Tissoires 		return sizeof(struct pad_report);
698*0412be1bSBenjamin Tissoires 	}
699*0412be1bSBenjamin Tissoires 
700*0412be1bSBenjamin Tissoires 	return 0;
701*0412be1bSBenjamin Tissoires }
702*0412be1bSBenjamin Tissoires 
703*0412be1bSBenjamin Tissoires HID_BPF_OPS(huion_kamvas16_gen3) = {
704*0412be1bSBenjamin Tissoires 	.hid_device_event = (void *)hid_fix_event_huion_kamvas16_gen3,
705*0412be1bSBenjamin Tissoires 	.hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas16_gen3,
706*0412be1bSBenjamin Tissoires };
707*0412be1bSBenjamin Tissoires 
708*0412be1bSBenjamin Tissoires SEC("syscall")
709*0412be1bSBenjamin Tissoires int probe(struct hid_bpf_probe_args *ctx)
710*0412be1bSBenjamin Tissoires {
711*0412be1bSBenjamin Tissoires 	switch (ctx->rdesc_size) {
712*0412be1bSBenjamin Tissoires 	case VENDOR_DESCRIPTOR_LENGTH:
713*0412be1bSBenjamin Tissoires 	case TABLET_DESCRIPTOR_LENGTH:
714*0412be1bSBenjamin Tissoires 	case WHEEL_DESCRIPTOR_LENGTH:
715*0412be1bSBenjamin Tissoires 		ctx->retval = 0;
716*0412be1bSBenjamin Tissoires 		break;
717*0412be1bSBenjamin Tissoires 	default:
718*0412be1bSBenjamin Tissoires 		ctx->retval = -EINVAL;
719*0412be1bSBenjamin Tissoires 	}
720*0412be1bSBenjamin Tissoires 
721*0412be1bSBenjamin Tissoires 	return 0;
722*0412be1bSBenjamin Tissoires }
723*0412be1bSBenjamin Tissoires 
724*0412be1bSBenjamin Tissoires char _license[] SEC("license") = "GPL";
725