xref: /linux/drivers/hid/bpf/progs/WALTOP__Batteryless-Tablet.bpf.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1*040adbe8SBenjamin Tissoires // SPDX-License-Identifier: GPL-2.0-only
2*040adbe8SBenjamin Tissoires /* Copyright (c) 2025 Red Hat
3*040adbe8SBenjamin Tissoires  */
4*040adbe8SBenjamin Tissoires 
5*040adbe8SBenjamin Tissoires #include "vmlinux.h"
6*040adbe8SBenjamin Tissoires #include "hid_bpf.h"
7*040adbe8SBenjamin Tissoires #include "hid_bpf_helpers.h"
8*040adbe8SBenjamin Tissoires #include <bpf/bpf_tracing.h>
9*040adbe8SBenjamin Tissoires 
10*040adbe8SBenjamin Tissoires #define VID_WALTOP 0x172F
11*040adbe8SBenjamin Tissoires #define PID_BATTERYLESS_TABLET 0x0505
12*040adbe8SBenjamin Tissoires 
13*040adbe8SBenjamin Tissoires HID_BPF_CONFIG(
14*040adbe8SBenjamin Tissoires 	HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_WALTOP, PID_BATTERYLESS_TABLET)
15*040adbe8SBenjamin Tissoires );
16*040adbe8SBenjamin Tissoires 
17*040adbe8SBenjamin Tissoires #define EXPECTED_RDESC_SIZE 335
18*040adbe8SBenjamin Tissoires #define PEN_REPORT_ID 16
19*040adbe8SBenjamin Tissoires 
20*040adbe8SBenjamin Tissoires #define TIP_SWITCH BIT(0)
21*040adbe8SBenjamin Tissoires #define BARREL_SWITCH BIT(1)
22*040adbe8SBenjamin Tissoires #define SECONDARY_BARREL_SWITCH BIT(5)
23*040adbe8SBenjamin Tissoires 
24*040adbe8SBenjamin Tissoires static __u8 last_button_state;
25*040adbe8SBenjamin Tissoires 
26*040adbe8SBenjamin Tissoires static const __u8 fixed_rdesc[] = {
27*040adbe8SBenjamin Tissoires 	0x05, 0x01,                    // Usage Page (Generic Desktop)
28*040adbe8SBenjamin Tissoires 	0x09, 0x02,                    // Usage (Mouse)
29*040adbe8SBenjamin Tissoires 	0xa1, 0x01,                    // Collection (Application)
30*040adbe8SBenjamin Tissoires 	0x85, 0x01,                    //   Report ID (1)
31*040adbe8SBenjamin Tissoires 	0x09, 0x01,                    //   Usage (Pointer)
32*040adbe8SBenjamin Tissoires 	0xa1, 0x00,                    //   Collection (Physical)
33*040adbe8SBenjamin Tissoires 	0x05, 0x09,                    //     Usage Page (Button)
34*040adbe8SBenjamin Tissoires 	0x19, 0x01,                    //     Usage Minimum (1)
35*040adbe8SBenjamin Tissoires 	0x29, 0x05,                    //     Usage Maximum (5)
36*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
37*040adbe8SBenjamin Tissoires 	0x25, 0x01,                    //     Logical Maximum (1)
38*040adbe8SBenjamin Tissoires 	0x75, 0x01,                    //     Report Size (1)
39*040adbe8SBenjamin Tissoires 	0x95, 0x05,                    //     Report Count (5)
40*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //     Input (Data,Var,Abs)
41*040adbe8SBenjamin Tissoires 	0x75, 0x03,                    //     Report Size (3)
42*040adbe8SBenjamin Tissoires 	0x95, 0x01,                    //     Report Count (1)
43*040adbe8SBenjamin Tissoires 	0x81, 0x03,                    //     Input (Cnst,Var,Abs)
44*040adbe8SBenjamin Tissoires 	0x05, 0x01,                    //     Usage Page (Generic Desktop)
45*040adbe8SBenjamin Tissoires 	0x09, 0x30,                    //     Usage (X)
46*040adbe8SBenjamin Tissoires 	0x09, 0x31,                    //     Usage (Y)
47*040adbe8SBenjamin Tissoires 	0x09, 0x38,                    //     Usage (Wheel)
48*040adbe8SBenjamin Tissoires 	0x15, 0x81,                    //     Logical Minimum (-127)
49*040adbe8SBenjamin Tissoires 	0x25, 0x7f,                    //     Logical Maximum (127)
50*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
51*040adbe8SBenjamin Tissoires 	0x95, 0x03,                    //     Report Count (3)
52*040adbe8SBenjamin Tissoires 	0x81, 0x06,                    //     Input (Data,Var,Rel)
53*040adbe8SBenjamin Tissoires 	0x05, 0x0c,                    //     Usage Page (Consumer)
54*040adbe8SBenjamin Tissoires 	0x15, 0x81,                    //     Logical Minimum (-127)
55*040adbe8SBenjamin Tissoires 	0x25, 0x7f,                    //     Logical Maximum (127)
56*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
57*040adbe8SBenjamin Tissoires 	0x95, 0x01,                    //     Report Count (1)
58*040adbe8SBenjamin Tissoires 	0x0a, 0x38, 0x02,              //     Usage (AC Pan)
59*040adbe8SBenjamin Tissoires 	0x81, 0x06,                    //     Input (Data,Var,Rel)
60*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
61*040adbe8SBenjamin Tissoires 	0xc0,                          // End Collection
62*040adbe8SBenjamin Tissoires 	0x05, 0x0d,                    // Usage Page (Digitizers)
63*040adbe8SBenjamin Tissoires 	0x09, 0x02,                    // Usage (Pen)
64*040adbe8SBenjamin Tissoires 	0xa1, 0x01,                    // Collection (Application)
65*040adbe8SBenjamin Tissoires 	0x85, 0x02,                    //   Report ID (2)
66*040adbe8SBenjamin Tissoires 	0x09, 0x20,                    //   Usage (Stylus)
67*040adbe8SBenjamin Tissoires 	0xa1, 0x00,                    //   Collection (Physical)
68*040adbe8SBenjamin Tissoires 	0x09, 0x00,                    //     Usage (0x0000)
69*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
70*040adbe8SBenjamin Tissoires 	0x26, 0xff, 0x00,              //     Logical Maximum (255)
71*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
72*040adbe8SBenjamin Tissoires 	0x95, 0x09,                    //     Report Count (9)
73*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //     Input (Data,Var,Abs)
74*040adbe8SBenjamin Tissoires 	0x09, 0x3f,                    //     Usage (Azimuth)
75*040adbe8SBenjamin Tissoires 	0x09, 0x40,                    //     Usage (Altitude)
76*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
77*040adbe8SBenjamin Tissoires 	0x26, 0xff, 0x00,              //     Logical Maximum (255)
78*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
79*040adbe8SBenjamin Tissoires 	0x95, 0x02,                    //     Report Count (2)
80*040adbe8SBenjamin Tissoires 	0xb1, 0x02,                    //     Feature (Data,Var,Abs)
81*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
82*040adbe8SBenjamin Tissoires 	0x85, 0x05,                    //   Report ID (5)
83*040adbe8SBenjamin Tissoires 	0x05, 0x0d,                    //   Usage Page (Digitizers)
84*040adbe8SBenjamin Tissoires 	0x09, 0x20,                    //   Usage (Stylus)
85*040adbe8SBenjamin Tissoires 	0xa1, 0x00,                    //   Collection (Physical)
86*040adbe8SBenjamin Tissoires 	0x09, 0x00,                    //     Usage (0x0000)
87*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
88*040adbe8SBenjamin Tissoires 	0x26, 0xff, 0x00,              //     Logical Maximum (255)
89*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
90*040adbe8SBenjamin Tissoires 	0x95, 0x07,                    //     Report Count (7)
91*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //     Input (Data,Var,Abs)
92*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
93*040adbe8SBenjamin Tissoires 	0x85, 0x0a,                    //   Report ID (10)
94*040adbe8SBenjamin Tissoires 	0x05, 0x0d,                    //   Usage Page (Digitizers)
95*040adbe8SBenjamin Tissoires 	0x09, 0x20,                    //   Usage (Stylus)
96*040adbe8SBenjamin Tissoires 	0xa1, 0x00,                    //   Collection (Physical)
97*040adbe8SBenjamin Tissoires 	0x09, 0x00,                    //     Usage (0x0000)
98*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
99*040adbe8SBenjamin Tissoires 	0x26, 0xff, 0x00,              //     Logical Maximum (255)
100*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
101*040adbe8SBenjamin Tissoires 	0x95, 0x07,                    //     Report Count (7)
102*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //     Input (Data,Var,Abs)
103*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
104*040adbe8SBenjamin Tissoires 	0x85, 0x10,                    //   Report ID (16)
105*040adbe8SBenjamin Tissoires 	0x09, 0x20,                    //   Usage (Stylus)
106*040adbe8SBenjamin Tissoires 	0xa1, 0x00,                    //   Collection (Physical)
107*040adbe8SBenjamin Tissoires 	0x09, 0x42,                    //     Usage (Tip Switch)
108*040adbe8SBenjamin Tissoires 	0x09, 0x44,                    //     Usage (Barrel Switch)
109*040adbe8SBenjamin Tissoires 	0x09, 0x3c,                    //     Usage (Invert)
110*040adbe8SBenjamin Tissoires 	0x09, 0x45,                    //     Usage (Eraser)
111*040adbe8SBenjamin Tissoires 	0x09, 0x32,                    //     Usage (In Range)
112*040adbe8SBenjamin Tissoires 	0x09, 0x5a,                    //     Usage (Secondary Barrel Switch)  <-- added
113*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
114*040adbe8SBenjamin Tissoires 	0x25, 0x01,                    //     Logical Maximum (1)
115*040adbe8SBenjamin Tissoires 	0x75, 0x01,                    //     Report Size (1)
116*040adbe8SBenjamin Tissoires 	0x95, 0x06,                    //     Report Count (6)                 <--- changed from 5
117*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //     Input (Data,Var,Abs)
118*040adbe8SBenjamin Tissoires 	0x95, 0x02,                    //     Report Count (2)                 <--- changed from 3
119*040adbe8SBenjamin Tissoires 	0x81, 0x03,                    //     Input (Cnst,Var,Abs)
120*040adbe8SBenjamin Tissoires 	0x05, 0x01,                    //     Usage Page (Generic Desktop)
121*040adbe8SBenjamin Tissoires 	0x09, 0x30,                    //     Usage (X)
122*040adbe8SBenjamin Tissoires 	0x75, 0x10,                    //     Report Size (16)
123*040adbe8SBenjamin Tissoires 	0x95, 0x01,                    //     Report Count (1)
124*040adbe8SBenjamin Tissoires 	0xa4,                          //     Push
125*040adbe8SBenjamin Tissoires 	0x55, 0x0d,                    //       Unit Exponent (-3)
126*040adbe8SBenjamin Tissoires 	0x65, 0x33,                    //       Unit (EnglishLinear: in³)
127*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //       Logical Minimum (0)
128*040adbe8SBenjamin Tissoires 	0x26, 0x00, 0x7d,              //       Logical Maximum (32000)
129*040adbe8SBenjamin Tissoires 	0x35, 0x00,                    //       Physical Minimum (0)
130*040adbe8SBenjamin Tissoires 	0x46, 0x00, 0x7d,              //       Physical Maximum (32000)
131*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //       Input (Data,Var,Abs)
132*040adbe8SBenjamin Tissoires 	0x09, 0x31,                    //       Usage (Y)
133*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //       Logical Minimum (0)
134*040adbe8SBenjamin Tissoires 	0x26, 0x20, 0x4e,              //       Logical Maximum (20000)
135*040adbe8SBenjamin Tissoires 	0x35, 0x00,                    //       Physical Minimum (0)
136*040adbe8SBenjamin Tissoires 	0x46, 0x20, 0x4e,              //       Physical Maximum (20000)
137*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //       Input (Data,Var,Abs)
138*040adbe8SBenjamin Tissoires 	0x05, 0x0d,                    //       Usage Page (Digitizers)
139*040adbe8SBenjamin Tissoires 	0x09, 0x30,                    //       Usage (Tip Pressure)
140*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //       Logical Minimum (0)
141*040adbe8SBenjamin Tissoires 	0x26, 0xff, 0x07,              //       Logical Maximum (2047)
142*040adbe8SBenjamin Tissoires 	0x35, 0x00,                    //       Physical Minimum (0)
143*040adbe8SBenjamin Tissoires 	0x46, 0xff, 0x07,              //       Physical Maximum (2047)
144*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //       Input (Data,Var,Abs)
145*040adbe8SBenjamin Tissoires 	0x05, 0x0d,                    //       Usage Page (Digitizers)
146*040adbe8SBenjamin Tissoires 	0x09, 0x3d,                    //       Usage (X Tilt)
147*040adbe8SBenjamin Tissoires 	0x09, 0x3e,                    //       Usage (Y Tilt)
148*040adbe8SBenjamin Tissoires 	0x15, 0xc4,                    //       Logical Minimum (-60)          <- changed from -127
149*040adbe8SBenjamin Tissoires 	0x25, 0x3c,                    //       Logical Maximum (60)           <- changed from 127
150*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //       Report Size (8)
151*040adbe8SBenjamin Tissoires 	0x95, 0x02,                    //       Report Count (2)
152*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //       Input (Data,Var,Abs)
153*040adbe8SBenjamin Tissoires 	0xc0,                          //     End Collection
154*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
155*040adbe8SBenjamin Tissoires 	0x05, 0x01,                    //   Usage Page (Generic Desktop)
156*040adbe8SBenjamin Tissoires 	0x09, 0x06,                    //   Usage (Keyboard)
157*040adbe8SBenjamin Tissoires 	0xa1, 0x01,                    //   Collection (Application)
158*040adbe8SBenjamin Tissoires 	0x85, 0x0d,                    //     Report ID (13)
159*040adbe8SBenjamin Tissoires 	0x05, 0x07,                    //     Usage Page (Keyboard/Keypad)
160*040adbe8SBenjamin Tissoires 	0x19, 0xe0,                    //     Usage Minimum (224)
161*040adbe8SBenjamin Tissoires 	0x29, 0xe7,                    //     Usage Maximum (231)
162*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
163*040adbe8SBenjamin Tissoires 	0x25, 0x01,                    //     Logical Maximum (1)
164*040adbe8SBenjamin Tissoires 	0x75, 0x01,                    //     Report Size (1)
165*040adbe8SBenjamin Tissoires 	0x95, 0x08,                    //     Report Count (8)
166*040adbe8SBenjamin Tissoires 	0x81, 0x02,                    //     Input (Data,Var,Abs)
167*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
168*040adbe8SBenjamin Tissoires 	0x95, 0x01,                    //     Report Count (1)
169*040adbe8SBenjamin Tissoires 	0x81, 0x01,                    //     Input (Cnst,Arr,Abs)
170*040adbe8SBenjamin Tissoires 	0x05, 0x07,                    //     Usage Page (Keyboard/Keypad)
171*040adbe8SBenjamin Tissoires 	0x19, 0x00,                    //     Usage Minimum (0)
172*040adbe8SBenjamin Tissoires 	0x29, 0x65,                    //     Usage Maximum (101)
173*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
174*040adbe8SBenjamin Tissoires 	0x25, 0x65,                    //     Logical Maximum (101)
175*040adbe8SBenjamin Tissoires 	0x75, 0x08,                    //     Report Size (8)
176*040adbe8SBenjamin Tissoires 	0x95, 0x05,                    //     Report Count (5)
177*040adbe8SBenjamin Tissoires 	0x81, 0x00,                    //     Input (Data,Arr,Abs)
178*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
179*040adbe8SBenjamin Tissoires 	0x05, 0x0c,                    //   Usage Page (Consumer)
180*040adbe8SBenjamin Tissoires 	0x09, 0x01,                    //   Usage (Consumer Control)
181*040adbe8SBenjamin Tissoires 	0xa1, 0x01,                    //   Collection (Application)
182*040adbe8SBenjamin Tissoires 	0x85, 0x0c,                    //     Report ID (12)
183*040adbe8SBenjamin Tissoires 	0x09, 0xe9,                    //     Usage (Volume Increment)
184*040adbe8SBenjamin Tissoires 	0x09, 0xea,                    //     Usage (Volume Decrement)
185*040adbe8SBenjamin Tissoires 	0x09, 0xe2,                    //     Usage (Mute)
186*040adbe8SBenjamin Tissoires 	0x15, 0x00,                    //     Logical Minimum (0)
187*040adbe8SBenjamin Tissoires 	0x25, 0x01,                    //     Logical Maximum (1)
188*040adbe8SBenjamin Tissoires 	0x75, 0x01,                    //     Report Size (1)
189*040adbe8SBenjamin Tissoires 	0x95, 0x03,                    //     Report Count (3)
190*040adbe8SBenjamin Tissoires 	0x81, 0x06,                    //     Input (Data,Var,Rel)
191*040adbe8SBenjamin Tissoires 	0x75, 0x05,                    //     Report Size (5)
192*040adbe8SBenjamin Tissoires 	0x95, 0x01,                    //     Report Count (1)
193*040adbe8SBenjamin Tissoires 	0x81, 0x07,                    //     Input (Cnst,Var,Rel)
194*040adbe8SBenjamin Tissoires 	0xc0,                          //   End Collection
195*040adbe8SBenjamin Tissoires };
196*040adbe8SBenjamin Tissoires 
197*040adbe8SBenjamin Tissoires static inline unsigned int bitwidth32(__u32 x)
198*040adbe8SBenjamin Tissoires {
199*040adbe8SBenjamin Tissoires 	return 32 - __builtin_clzg(x, 32);
200*040adbe8SBenjamin Tissoires }
201*040adbe8SBenjamin Tissoires 
202*040adbe8SBenjamin Tissoires static inline unsigned int floor_log2_32(__u32 x)
203*040adbe8SBenjamin Tissoires {
204*040adbe8SBenjamin Tissoires 	return bitwidth32(x) - 1;
205*040adbe8SBenjamin Tissoires }
206*040adbe8SBenjamin Tissoires 
207*040adbe8SBenjamin Tissoires /* Maps the interval [0, 2047] to itself using a scaled
208*040adbe8SBenjamin Tissoires  * approximation of the function log2(x+1).
209*040adbe8SBenjamin Tissoires  */
210*040adbe8SBenjamin Tissoires static unsigned int scaled_log2(__u16 v)
211*040adbe8SBenjamin Tissoires {
212*040adbe8SBenjamin Tissoires 	const unsigned int XMAX = 2047;
213*040adbe8SBenjamin Tissoires 	const unsigned int YMAX = 11; /* log2(2048) = 11 */
214*040adbe8SBenjamin Tissoires 
215*040adbe8SBenjamin Tissoires 	unsigned int x = v + 1;
216*040adbe8SBenjamin Tissoires 	unsigned int n = floor_log2_32(x);
217*040adbe8SBenjamin Tissoires 	unsigned int b = 1 << n;
218*040adbe8SBenjamin Tissoires 
219*040adbe8SBenjamin Tissoires 	/* Fixed-point fraction in [0, 1), linearly
220*040adbe8SBenjamin Tissoires 	 * interpolated using delta-y = 1 and
221*040adbe8SBenjamin Tissoires 	 * delta-x = (2b - b) = b.
222*040adbe8SBenjamin Tissoires 	 */
223*040adbe8SBenjamin Tissoires 	unsigned int frac = (x - b) << YMAX;
224*040adbe8SBenjamin Tissoires 	unsigned int lerp = frac / b;
225*040adbe8SBenjamin Tissoires 	unsigned int log2 = (n << YMAX) + lerp;
226*040adbe8SBenjamin Tissoires 
227*040adbe8SBenjamin Tissoires 	return ((log2 * XMAX) / YMAX) >> YMAX;
228*040adbe8SBenjamin Tissoires }
229*040adbe8SBenjamin Tissoires 
230*040adbe8SBenjamin Tissoires SEC(HID_BPF_RDESC_FIXUP)
231*040adbe8SBenjamin Tissoires int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
232*040adbe8SBenjamin Tissoires {
233*040adbe8SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
234*040adbe8SBenjamin Tissoires 
235*040adbe8SBenjamin Tissoires 	if (!data)
236*040adbe8SBenjamin Tissoires 		return 0; /* EPERM check */
237*040adbe8SBenjamin Tissoires 
238*040adbe8SBenjamin Tissoires 	__builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc));
239*040adbe8SBenjamin Tissoires 
240*040adbe8SBenjamin Tissoires 	return sizeof(fixed_rdesc);
241*040adbe8SBenjamin Tissoires }
242*040adbe8SBenjamin Tissoires 
243*040adbe8SBenjamin Tissoires SEC(HID_BPF_DEVICE_EVENT)
244*040adbe8SBenjamin Tissoires int BPF_PROG(waltop_fix_events, struct hid_bpf_ctx *hctx)
245*040adbe8SBenjamin Tissoires {
246*040adbe8SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
247*040adbe8SBenjamin Tissoires 
248*040adbe8SBenjamin Tissoires 	if (!data)
249*040adbe8SBenjamin Tissoires 		return 0; /* EPERM check */
250*040adbe8SBenjamin Tissoires 
251*040adbe8SBenjamin Tissoires 	__u8 report_id = data[0];
252*040adbe8SBenjamin Tissoires 
253*040adbe8SBenjamin Tissoires 	if (report_id != PEN_REPORT_ID)
254*040adbe8SBenjamin Tissoires 		return 0;
255*040adbe8SBenjamin Tissoires 
256*040adbe8SBenjamin Tissoires 	/* On this tablet if the secondary barrel switch is pressed,
257*040adbe8SBenjamin Tissoires 	 * the tablet sends tip down and barrel down. Change this to
258*040adbe8SBenjamin Tissoires 	 * just secondary barrel down when there is no ambiguity.
259*040adbe8SBenjamin Tissoires 	 *
260*040adbe8SBenjamin Tissoires 	 * It's possible that there is a bug in the firmware and the
261*040adbe8SBenjamin Tissoires 	 * device intends to set invert + eraser instead (i.e. the
262*040adbe8SBenjamin Tissoires 	 * pysical button is an eraser button) but since
263*040adbe8SBenjamin Tissoires 	 * the pressure is always zero, said eraser button
264*040adbe8SBenjamin Tissoires 	 * would be useless anyway.
265*040adbe8SBenjamin Tissoires 	 *
266*040adbe8SBenjamin Tissoires 	 * So let's just change the button to secondary barrel down.
267*040adbe8SBenjamin Tissoires 	 */
268*040adbe8SBenjamin Tissoires 
269*040adbe8SBenjamin Tissoires 	__u8 tip_switch = data[1] & TIP_SWITCH;
270*040adbe8SBenjamin Tissoires 	__u8 barrel_switch = data[1] & BARREL_SWITCH;
271*040adbe8SBenjamin Tissoires 
272*040adbe8SBenjamin Tissoires 	__u8 tip_held = last_button_state & TIP_SWITCH;
273*040adbe8SBenjamin Tissoires 	__u8 barrel_held = last_button_state & BARREL_SWITCH;
274*040adbe8SBenjamin Tissoires 
275*040adbe8SBenjamin Tissoires 	if (tip_switch && barrel_switch && !tip_held && !barrel_held) {
276*040adbe8SBenjamin Tissoires 		data[1] &= ~(TIP_SWITCH | BARREL_SWITCH); /* release tip and barrel */
277*040adbe8SBenjamin Tissoires 		data[1] |= SECONDARY_BARREL_SWITCH; /* set secondary barrel switch */
278*040adbe8SBenjamin Tissoires 	}
279*040adbe8SBenjamin Tissoires 
280*040adbe8SBenjamin Tissoires 	last_button_state = data[1];
281*040adbe8SBenjamin Tissoires 
282*040adbe8SBenjamin Tissoires 	/* The pressure sensor on this tablet maps around half of the
283*040adbe8SBenjamin Tissoires 	 * logical pressure range into the interval [0-100]. Further
284*040adbe8SBenjamin Tissoires 	 * pressure causes the sensor value to increase exponentially
285*040adbe8SBenjamin Tissoires 	 * up to a maximum value of 2047.
286*040adbe8SBenjamin Tissoires 	 *
287*040adbe8SBenjamin Tissoires 	 * The values 12 and 102 were chosen to have an integer slope
288*040adbe8SBenjamin Tissoires 	 * with smooth transition between the two curves around the
289*040adbe8SBenjamin Tissoires 	 * value 100.
290*040adbe8SBenjamin Tissoires 	 */
291*040adbe8SBenjamin Tissoires 
292*040adbe8SBenjamin Tissoires 	__u16 pressure = (((__u16)data[6]) << 0) | (((__u16)data[7]) << 8);
293*040adbe8SBenjamin Tissoires 
294*040adbe8SBenjamin Tissoires 	if (pressure <= 102)
295*040adbe8SBenjamin Tissoires 		pressure *= 12;
296*040adbe8SBenjamin Tissoires 	else
297*040adbe8SBenjamin Tissoires 		pressure = scaled_log2(pressure);
298*040adbe8SBenjamin Tissoires 
299*040adbe8SBenjamin Tissoires 	data[6] = pressure >> 0;
300*040adbe8SBenjamin Tissoires 	data[7] = pressure >> 8;
301*040adbe8SBenjamin Tissoires 
302*040adbe8SBenjamin Tissoires 	return 0;
303*040adbe8SBenjamin Tissoires }
304*040adbe8SBenjamin Tissoires 
305*040adbe8SBenjamin Tissoires HID_BPF_OPS(waltop_batteryless) = {
306*040adbe8SBenjamin Tissoires 	.hid_device_event = (void *)waltop_fix_events,
307*040adbe8SBenjamin Tissoires 	.hid_rdesc_fixup = (void *)hid_fix_rdesc,
308*040adbe8SBenjamin Tissoires };
309*040adbe8SBenjamin Tissoires 
310*040adbe8SBenjamin Tissoires SEC("syscall")
311*040adbe8SBenjamin Tissoires int probe(struct hid_bpf_probe_args *ctx)
312*040adbe8SBenjamin Tissoires {
313*040adbe8SBenjamin Tissoires 	if (ctx->rdesc_size == EXPECTED_RDESC_SIZE)
314*040adbe8SBenjamin Tissoires 		ctx->retval = 0;
315*040adbe8SBenjamin Tissoires 	else
316*040adbe8SBenjamin Tissoires 		ctx->retval = -EINVAL;
317*040adbe8SBenjamin Tissoires 
318*040adbe8SBenjamin Tissoires 	return 0;
319*040adbe8SBenjamin Tissoires }
320*040adbe8SBenjamin Tissoires 
321*040adbe8SBenjamin Tissoires char _license[] SEC("license") = "GPL";
322