Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hid/bpf/progs/XPPen__Deco02.bpf.c
38241 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
3
#include "vmlinux.h"
4
#include "hid_bpf.h"
5
#include "hid_bpf_helpers.h"
6
#include "hid_report_helpers.h"
7
#include <bpf/bpf_tracing.h>
8
9
#define VID_UGEE 0x28BD
10
#define PID_DECO_02 0x0803
11
12
HID_BPF_CONFIG(
13
HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_02),
14
);
15
16
/*
17
* Devices are:
18
* - Pad input, including pen (This is the only one we are interested in)
19
* - Pen input as mouse
20
* - Vendor
21
*
22
* Descriptors on main device are:
23
* - 7: Pen
24
* - 6: Vendor settings? Unclear
25
* - 3: Keyboard (This is what we want to modify)
26
* - 5: Feature report
27
*
28
* This creates three event nodes:
29
* - XP-PEN DECO 02 Stylus
30
* - XP-PEN DECO 02
31
* - XP-PEN DECO 02 Keyboard (Again, what we want to modify)
32
*
33
* # Report descriptor length: 188 bytes
34
* # 0x05, 0x0d, // Usage Page (Digitizers) 0
35
* # 0x09, 0x02, // Usage (Pen) 2
36
* # 0xa1, 0x01, // Collection (Application) 4
37
* # 0x85, 0x07, // Report ID (7) 6
38
* # 0x09, 0x20, // Usage (Stylus) 8
39
* # 0xa1, 0x00, // Collection (Physical) 10
40
* # 0x09, 0x42, // Usage (Tip Switch) 12
41
* # 0x09, 0x44, // Usage (Barrel Switch) 14
42
* # 0x09, 0x45, // Usage (Eraser) 16
43
* # 0x09, 0x3c, // Usage (Invert) 18
44
* # 0x09, 0x32, // Usage (In Range) 20
45
* # 0x15, 0x00, // Logical Minimum (0) 22
46
* # 0x25, 0x01, // Logical Maximum (1) 24
47
* # 0x75, 0x01, // Report Size (1) 26
48
* # 0x95, 0x05, // Report Count (5) 28
49
* # 0x81, 0x02, // Input (Data,Var,Abs) 30
50
* # 0x95, 0x03, // Report Count (3) 32
51
* # 0x81, 0x03, // Input (Cnst,Var,Abs) 34
52
* # 0x05, 0x01, // Usage Page (Generic Desktop) 36
53
* # 0x09, 0x30, // Usage (X) 38
54
* # 0x15, 0x00, // Logical Minimum (0) 40
55
* # 0x26, 0x50, 0x57, // Logical Maximum (22352) 42
56
* # 0x55, 0x0d, // Unit Exponent (-3) 45
57
* # 0x65, 0x13, // Unit (EnglishLinear: in) 47
58
* # 0x35, 0x00, // Physical Minimum (0) 49
59
* # 0x46, 0x50, 0x57, // Physical Maximum (22352) 51
60
* # 0x75, 0x10, // Report Size (16) 54
61
* # 0x95, 0x01, // Report Count (1) 56
62
* # 0x81, 0x02, // Input (Data,Var,Abs) 58
63
* # 0x09, 0x31, // Usage (Y) 60
64
* # 0x15, 0x00, // Logical Minimum (0) 62
65
* # 0x26, 0x92, 0x36, // Logical Maximum (13970) 64
66
* # 0x55, 0x0d, // Unit Exponent (-3) 67
67
* # 0x65, 0x13, // Unit (EnglishLinear: in) 69
68
* # 0x35, 0x00, // Physical Minimum (0) 71
69
* # 0x46, 0x92, 0x36, // Physical Maximum (13970) 73
70
* # 0x75, 0x10, // Report Size (16) 76
71
* # 0x95, 0x01, // Report Count (1) 78
72
* # 0x81, 0x02, // Input (Data,Var,Abs) 80
73
* # 0x05, 0x0d, // Usage Page (Digitizers) 82
74
* # 0x09, 0x30, // Usage (Tip Pressure) 84
75
* # 0x15, 0x00, // Logical Minimum (0) 86
76
* # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 88
77
* # 0x75, 0x10, // Report Size (16) 91
78
* # 0x95, 0x01, // Report Count (1) 93
79
* # 0x81, 0x02, // Input (Data,Var,Abs) 95
80
* # 0xc0, // End Collection 97
81
* # 0xc0, // End Collection 98
82
* # 0x09, 0x0e, // Usage (Device Configuration) 99
83
* # 0xa1, 0x01, // Collection (Application) 101
84
* # 0x85, 0x05, // Report ID (5) 103
85
* # 0x09, 0x23, // Usage (Device Settings) 105
86
* # 0xa1, 0x02, // Collection (Logical) 107
87
* # 0x09, 0x52, // Usage (Inputmode) 109
88
* # 0x09, 0x53, // Usage (Device Index) 111
89
* # 0x25, 0x0a, // Logical Maximum (10) 113
90
* # 0x75, 0x08, // Report Size (8) 115
91
* # 0x95, 0x02, // Report Count (2) 117
92
* # 0xb1, 0x02, // Feature (Data,Var,Abs) 119
93
* # 0xc0, // End Collection 121
94
* # 0xc0, // End Collection 122
95
* # 0x05, 0x0c, // Usage Page (Consumer Devices) 123
96
* # 0x09, 0x36, // Usage (Function Buttons) 125
97
* # 0xa1, 0x00, // Collection (Physical) 127
98
* # 0x85, 0x06, // Report ID (6) 129
99
* # 0x05, 0x09, // Usage Page (Button) 131
100
* # 0x19, 0x01, // Usage Minimum (1) 133
101
* # 0x29, 0x20, // Usage Maximum (32) 135
102
* # 0x15, 0x00, // Logical Minimum (0) 137
103
* # 0x25, 0x01, // Logical Maximum (1) 139
104
* # 0x95, 0x20, // Report Count (32) 141
105
* # 0x75, 0x01, // Report Size (1) 143
106
* # 0x81, 0x02, // Input (Data,Var,Abs) 145
107
* # 0xc0, // End Collection 147
108
* # 0x05, 0x01, // Usage Page (Generic Desktop) 148
109
* # 0x09, 0x06, // Usage (Keyboard) 150
110
* # 0xa1, 0x01, // Collection (Application) 152
111
* # 0x85, 0x03, // Report ID (3) 154
112
* # 0x05, 0x07, // Usage Page (Keyboard) 156
113
* # 0x19, 0xe0, // Usage Minimum (224) 158
114
* # 0x29, 0xe7, // Usage Maximum (231) 160
115
* # 0x15, 0x00, // Logical Minimum (0) 162
116
* # 0x25, 0x01, // Logical Maximum (1) 164
117
* # 0x75, 0x01, // Report Size (1) 166
118
* # 0x95, 0x08, // Report Count (8) 168
119
* # 0x81, 0x02, // Input (Data,Var,Abs) 170
120
* # 0x05, 0x07, // Usage Page (Keyboard) 172
121
* # 0x19, 0x00, // Usage Minimum (0) 174
122
* # 0x29, 0xff, // Usage Maximum (255) 176
123
* # 0x26, 0xff, 0x00, // Logical Maximum (255) 178
124
* # 0x75, 0x08, // Report Size (8) 181
125
* # 0x95, 0x06, // Report Count (6) 183
126
* # 0x81, 0x00, // Input (Data,Arr,Abs) 185
127
* # 0xc0, // End Collection 187
128
*
129
* Key events; top to bottom:
130
* Buttons released: 03 00 00 00 00 00 00 00
131
* Button1: 03 00 05 00 00 00 00 00 -> 'b and B'
132
* Button2: 03 00 2c 00 00 00 00 00 -> 'Spacebar'
133
* Button3: 03 00 08 00 00 00 00 00 -> 'e and E'
134
* Button4: 03 00 0c 00 00 00 00 00 -> 'i and I'
135
* Button5: 03 05 1d 00 00 00 00 00 -> LeftControl + LeftAlt + 'z and Z'
136
* Button6: 03 01 16 00 00 00 00 00 -> LeftControl + 's and S'
137
*
138
* Dial Events:
139
* Clockwise: 03 01 2e 00 00 00 00 00 -> LeftControl + '= and +'
140
* Anticlockwise: 03 01 2d 00 00 00 00 00 -> LeftControl + '- and (underscore)'
141
*
142
* NOTE: Input event descriptions begin at byte 2, and progressively build
143
* towards byte 7 as each new key is pressed maintaining the press order.
144
* For example:
145
* BTN1 followed by BTN2 is 03 00 05 2c 00 00 00 00
146
* BTN2 followed by BTN1 is 03 00 2c 05 00 00 00 00
147
*
148
* Releasing a button causes its byte to be freed, and the next item in the list
149
* is pushed forwards. Dial events are released immediately after an event is
150
* registered (i.e. after each "click"), so will continually appear pushed
151
* backwards in the report.
152
*
153
* When a button with a modifier key is pressed, the button identifier stacks in
154
* an abnormal way, where the highest modifier byte always supersedes others.
155
* In these cases, the button with the higher modifier is always last.
156
* For example:
157
* BTN6 followed by BTN5 is 03 05 1d 16 00 00 00 00
158
* BTN5 followed by BTN6 is 03 05 1d 16 00 00 00 00
159
* BTN5 followed by BTN1 is 03 05 05 1d 00 00 00 00
160
*
161
* For three button presses in order, demonstrating strictly above rules:
162
* BTN6, BTN1, BTN5 is 03 05 05 1d 16 00 00 00
163
* BTN5, BTN1, BTN6 is 03 05 05 1d 16 00 00 00
164
*
165
* In short, when BTN5/6 are pressed, the order of operations is lost, as they
166
* will always float to the end when pressed in combination with others.
167
*
168
* Fortunately, all states are recorded in the same way, with no overlaps.
169
* Byte 1 can be used as a spare for the wheel, since this is for mod keys.
170
*/
171
172
#define RDESC_SIZE_PAD 188
173
#define REPORT_SIZE_PAD 8
174
#define REPORT_ID_BUTTONS 3
175
#define PAD_BUTTON_COUNT 6
176
#define RDESC_KEYBOARD_OFFSET 148
177
178
static const __u8 fixed_rdesc_pad[] = {
179
/* Copy of pen descriptor to avoid losing functionality */
180
UsagePage_Digitizers
181
Usage_Dig_Pen
182
CollectionApplication(
183
ReportId(7)
184
Usage_Dig_Stylus
185
CollectionPhysical(
186
Usage_Dig_TipSwitch
187
Usage_Dig_BarrelSwitch
188
Usage_Dig_Eraser
189
Usage_Dig_Invert
190
Usage_Dig_InRange
191
LogicalMinimum_i8(0)
192
LogicalMaximum_i8(1)
193
ReportSize(1)
194
ReportCount(5)
195
Input(Var|Abs)
196
ReportCount(3)
197
Input(Const) /* Input (Const, Var, Abs) */
198
UsagePage_GenericDesktop
199
Usage_GD_X
200
LogicalMinimum_i16(0)
201
LogicalMaximum_i16(22352)
202
UnitExponent(-3)
203
Unit(in) /* (EnglishLinear: in) */
204
PhysicalMinimum_i16(0)
205
PhysicalMaximum_i16(22352)
206
ReportSize(16)
207
ReportCount(1)
208
Input(Var|Abs)
209
Usage_GD_Y
210
LogicalMinimum_i16(0)
211
LogicalMaximum_i16(13970)
212
UnitExponent(-3)
213
Unit(in) /* (EnglishLinear: in) */
214
PhysicalMinimum_i16(0)
215
PhysicalMaximum_i16(13970)
216
ReportSize(16)
217
ReportCount(1)
218
Input(Var|Abs)
219
UsagePage_Digitizers
220
Usage_Dig_TipPressure
221
LogicalMinimum_i16(0)
222
LogicalMaximum_i16(8191)
223
ReportSize(16)
224
ReportCount(1)
225
Input(Var|Abs)
226
)
227
)
228
229
/* FIXES BEGIN */
230
UsagePage_GenericDesktop
231
Usage_GD_Keypad
232
CollectionApplication(
233
ReportId(REPORT_ID_BUTTONS) /* Retain original ID on byte 0 */
234
ReportCount(1)
235
ReportSize(REPORT_SIZE_PAD)
236
UsagePage_Digitizers
237
Usage_Dig_TabletFunctionKeys
238
CollectionPhysical(
239
/* Byte 1: Dial state */
240
UsagePage_GenericDesktop
241
Usage_GD_Dial
242
LogicalMinimum_i8(-1)
243
LogicalMaximum_i8(1)
244
ReportCount(1)
245
ReportSize(REPORT_SIZE_PAD)
246
Input(Var|Rel)
247
/* Byte 2: Button state */
248
UsagePage_Button
249
ReportSize(1)
250
ReportCount(PAD_BUTTON_COUNT)
251
UsageMinimum_i8(0x01)
252
UsageMaximum_i8(PAD_BUTTON_COUNT) /* Number of buttons */
253
LogicalMinimum_i8(0x0)
254
LogicalMaximum_i8(0x1)
255
Input(Var|Abs)
256
/* Byte 3: Exists to be tablet pad */
257
UsagePage_Digitizers
258
Usage_Dig_BarrelSwitch
259
ReportCount(1)
260
ReportSize(1)
261
Input(Var|Abs)
262
ReportCount(7) /* Padding, to fill full report space */
263
Input(Const)
264
/* Byte 4/5: Exists to be a tablet pad */
265
UsagePage_GenericDesktop
266
Usage_GD_X
267
Usage_GD_Y
268
ReportCount(2)
269
ReportSize(8)
270
Input(Var|Abs)
271
/* Bytes 6/7: Padding, to match original length */
272
ReportCount(2)
273
ReportSize(8)
274
Input(Const)
275
)
276
FixedSizeVendorReport(RDESC_SIZE_PAD)
277
)
278
};
279
280
SEC(HID_BPF_RDESC_FIXUP)
281
int BPF_PROG(xppen_deco02_rdesc_fixup, struct hid_bpf_ctx *hctx)
282
{
283
__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
284
285
if (!data)
286
return 0; /* EPERM Check */
287
288
if (hctx->size == RDESC_SIZE_PAD) {
289
__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
290
return sizeof(fixed_rdesc_pad);
291
}
292
293
return 0;
294
}
295
296
SEC(HID_BPF_DEVICE_EVENT)
297
int BPF_PROG(xppen_deco02_device_event, struct hid_bpf_ctx *hctx)
298
{
299
__u8 *data = hid_bpf_get_data(hctx, 0, REPORT_SIZE_PAD);
300
301
if (!data || data[0] != REPORT_ID_BUTTONS)
302
return 0; /* EPERM or wrong report */
303
304
__u8 dial_code = 0;
305
__u8 button_mask = 0;
306
size_t d;
307
308
/* Start from 2; 0 is report ID, 1 is modifier keys, replaced by dial */
309
for (d = 2; d < 8; d++) {
310
switch (data[d]) {
311
case 0x2e:
312
dial_code = 1;
313
break;
314
case 0x2d:
315
dial_code = -1;
316
break;
317
/* below are buttons, top to bottom */
318
case 0x05:
319
button_mask |= BIT(0);
320
break;
321
case 0x2c:
322
button_mask |= BIT(1);
323
break;
324
case 0x08:
325
button_mask |= BIT(2);
326
break;
327
case 0x0c:
328
button_mask |= BIT(3);
329
break;
330
case 0x1d:
331
button_mask |= BIT(4);
332
break;
333
case 0x16:
334
button_mask |= BIT(05);
335
break;
336
default:
337
break;
338
}
339
}
340
341
__u8 report[8] = { REPORT_ID_BUTTONS, dial_code, button_mask, 0x00 };
342
343
__builtin_memcpy(data, report, sizeof(report));
344
return 0;
345
}
346
347
HID_BPF_OPS(xppen_deco02) = {
348
.hid_rdesc_fixup = (void *)xppen_deco02_rdesc_fixup,
349
.hid_device_event = (void *)xppen_deco02_device_event,
350
};
351
352
SEC("syscall")
353
int probe(struct hid_bpf_probe_args *ctx)
354
{
355
ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD ? -EINVAL : 0;
356
return 0;
357
}
358
359
char _license[] SEC("license") = "GPL";
360
361