Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c
53517 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/* Copyright (c) 2024 Red Hat, Inc
3
*/
4
5
#include "vmlinux.h"
6
#include "hid_bpf.h"
7
#include "hid_bpf_helpers.h"
8
#include "hid_report_helpers.h"
9
#include <bpf/bpf_tracing.h>
10
11
#define VID_HUION 0x256C
12
#define PID_INSPIROY_2_S 0x0066
13
14
HID_BPF_CONFIG(
15
HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_2_S),
16
);
17
18
/* Filled in by udev-hid-bpf */
19
char UDEV_PROP_HUION_FIRMWARE_ID[64];
20
21
/* The prefix of the firmware ID we expect for this device. The full firmware
22
* string has a date suffix, e.g. HUION_T21j_221221
23
*/
24
char EXPECTED_FIRMWARE_ID[] = "HUION_T21j_";
25
26
/* How this BPF program works: the tablet has two modes, firmware mode and
27
* tablet mode. In firmware mode (out of the box) the tablet sends button events
28
* and the dial as keyboard combinations. In tablet mode it uses a vendor specific
29
* hid report to report everything instead.
30
* Depending on the mode some hid reports are never sent and the corresponding
31
* devices are mute.
32
*
33
* To switch the tablet use e.g. https://github.com/whot/huion-switcher
34
* or one of the tools from the digimend project
35
*
36
* This BPF works for both modes. The huion-switcher tool sets the
37
* HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware
38
* pad and pen reports (by making them vendor collections that are ignored).
39
* If that property is not set we fix all hidraw nodes so the tablet works in
40
* either mode though the drawback is that the device will show up twice if
41
* you bind it to all event nodes
42
*
43
* Default report descriptor for the first exposed hidraw node:
44
*
45
* # HUION Huion Tablet_H641P
46
* # Report descriptor length: 18 bytes
47
* # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 0xFF00) 0
48
* # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3
49
* # 0xa1, 0x01, // Collection (Application) 5
50
* # 0x85, 0x08, // Report ID (8) 7
51
* # 0x75, 0x58, // Report Size (88) 9
52
* # 0x95, 0x01, // Report Count (1) 11
53
* # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13
54
* # 0x81, 0x02, // Input (Data,Var,Abs) 15
55
* # 0xc0, // End Collection 17
56
* R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0
57
*
58
* This rdesc does nothing until the tablet is switched to raw mode, see
59
* https://github.com/whot/huion-switcher
60
*
61
*
62
* Second hidraw node is the Pen. This one sends events until the tablet is
63
* switched to raw mode, then it's mute.
64
*
65
* # Report descriptor length: 93 bytes
66
* # 0x05, 0x0d, // Usage Page (Digitizers) 0
67
* # 0x09, 0x02, // Usage (Pen) 2
68
* # 0xa1, 0x01, // Collection (Application) 4
69
* # 0x85, 0x0a, // Report ID (10) 6
70
* # 0x09, 0x20, // Usage (Stylus) 8
71
* # 0xa1, 0x01, // Collection (Application) 10
72
* # 0x09, 0x42, // Usage (Tip Switch) 12
73
* # 0x09, 0x44, // Usage (Barrel Switch) 14
74
* # 0x09, 0x45, // Usage (Eraser) 16
75
* # 0x09, 0x3c, // Usage (Invert) 18 <-- has no Invert eraser
76
* # 0x15, 0x00, // Logical Minimum (0) 20
77
* # 0x25, 0x01, // Logical Maximum (1) 22
78
* # 0x75, 0x01, // Report Size (1) 24
79
* # 0x95, 0x06, // Report Count (6) 26
80
* # 0x81, 0x02, // Input (Data,Var,Abs) 28
81
* # 0x09, 0x32, // Usage (In Range) 30
82
* # 0x75, 0x01, // Report Size (1) 32
83
* # 0x95, 0x01, // Report Count (1) 34
84
* # 0x81, 0x02, // Input (Data,Var,Abs) 36
85
* # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
86
* # 0x05, 0x01, // Usage Page (Generic Desktop) 40
87
* # 0x09, 0x30, // Usage (X) 42
88
* # 0x09, 0x31, // Usage (Y) 44
89
* # 0x55, 0x0d, // Unit Exponent (-3) 46 <-- change to -2
90
* # 0x65, 0x33, // Unit (EnglishLinear: in³) 48 <-- change in³ to in
91
* # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 50
92
* # 0x35, 0x00, // Physical Minimum (0) 53
93
* # 0x46, 0x00, 0x08, // Physical Maximum (2048) 55 <-- invalid size
94
* # 0x75, 0x10, // Report Size (16) 58
95
* # 0x95, 0x02, // Report Count (2) 60
96
* # 0x81, 0x02, // Input (Data,Var,Abs) 62
97
* # 0x05, 0x0d, // Usage Page (Digitizers) 64
98
* # 0x09, 0x30, // Usage (Tip Pressure) 66
99
* # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 68
100
* # 0x75, 0x10, // Report Size (16) 71
101
* # 0x95, 0x01, // Report Count (1) 73
102
* # 0x81, 0x02, // Input (Data,Var,Abs) 75
103
* # 0x09, 0x3d, // Usage (X Tilt) 77 <-- No tilt reported
104
* # 0x09, 0x3e, // Usage (Y Tilt) 79
105
* # 0x15, 0x81, // Logical Minimum (-127) 81
106
* # 0x25, 0x7f, // Logical Maximum (127) 83
107
* # 0x75, 0x08, // Report Size (8) 85
108
* # 0x95, 0x02, // Report Count (2) 87
109
* # 0x81, 0x02, // Input (Data,Var,Abs) 89
110
* # 0xc0, // End Collection 91
111
* # 0xc0, // End Collection 92
112
* R: 93 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 45 09 3c 15 00 25 01 7501 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 09 3d09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0
113
*
114
* Third hidraw node is the pad which sends a combination of keyboard shortcuts until
115
* the tablet is switched to raw mode, then it's mute:
116
*
117
* # Report descriptor length: 65 bytes
118
* # 0x05, 0x01, // Usage Page (Generic Desktop) 0
119
* # 0x09, 0x06, // Usage (Keyboard) 2
120
* # 0xa1, 0x01, // Collection (Application) 4
121
* # 0x85, 0x03, // Report ID (3) 6
122
* # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8
123
* # 0x19, 0xe0, // UsageMinimum (224) 10
124
* # 0x29, 0xe7, // UsageMaximum (231) 12
125
* # 0x15, 0x00, // Logical Minimum (0) 14
126
* # 0x25, 0x01, // Logical Maximum (1) 16
127
* # 0x75, 0x01, // Report Size (1) 18
128
* # 0x95, 0x08, // Report Count (8) 20
129
* # 0x81, 0x02, // Input (Data,Var,Abs) 22
130
* # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 24
131
* # 0x19, 0x00, // UsageMinimum (0) 26
132
* # 0x29, 0xff, // UsageMaximum (255) 28
133
* # 0x26, 0xff, 0x00, // Logical Maximum (255) 30
134
* # 0x75, 0x08, // Report Size (8) 33
135
* # 0x95, 0x06, // Report Count (6) 35
136
* # 0x81, 0x00, // Input (Data,Arr,Abs) 37
137
* # 0xc0, // End Collection 39
138
* # 0x05, 0x0c, // Usage Page (Consumer) 40
139
* # 0x09, 0x01, // Usage (Consumer Control) 42
140
* # 0xa1, 0x01, // Collection (Application) 44
141
* # 0x85, 0x04, // Report ID (4) 46
142
* # 0x19, 0x00, // UsageMinimum (0) 48
143
* # 0x2a, 0x3c, 0x02, // UsageMaximum (572) 50
144
* # 0x15, 0x00, // Logical Minimum (0) 53
145
* # 0x26, 0x3c, 0x02, // Logical Maximum (572) 55
146
* # 0x95, 0x01, // Report Count (1) 58
147
* # 0x75, 0x10, // Report Size (16) 60
148
* # 0x81, 0x00, // Input (Data,Arr,Abs) 62
149
* # 0xc0, // End Collection 64
150
* R: 65 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 0507 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 00 2a 3c02 15 00 26 3c 02 95 01 75 10 81 00 c0
151
* N: HUION Huion Tablet_H641P
152
*/
153
154
#define PAD_REPORT_DESCRIPTOR_LENGTH 65
155
#define PEN_REPORT_DESCRIPTOR_LENGTH 93
156
#define VENDOR_REPORT_DESCRIPTOR_LENGTH 18
157
#define PAD_REPORT_ID 3
158
#define PEN_REPORT_ID 10
159
#define VENDOR_REPORT_ID 8
160
#define PAD_REPORT_LENGTH 8
161
#define PEN_REPORT_LENGTH 10
162
#define VENDOR_REPORT_LENGTH 12
163
164
165
__u8 last_button_state;
166
__u8 last_tip_state;
167
__u8 last_sec_barrel_state;
168
__u8 force_tip_down_count;
169
170
static const __u8 fixed_rdesc_pad[] = {
171
UsagePage_GenericDesktop
172
Usage_GD_Keypad
173
CollectionApplication(
174
// -- Byte 0 in report
175
ReportId(PAD_REPORT_ID)
176
LogicalMinimum_i8(0)
177
LogicalMaximum_i8(1)
178
UsagePage_Digitizers
179
Usage_Dig_TabletFunctionKeys
180
CollectionPhysical(
181
// Byte 1 in report - just exists so we get to be a tablet pad
182
Usage_Dig_BarrelSwitch // BTN_STYLUS
183
ReportCount(1)
184
ReportSize(1)
185
Input(Var|Abs)
186
ReportCount(7) // padding
187
Input(Const)
188
// Bytes 2/3 in report - just exists so we get to be a tablet pad
189
UsagePage_GenericDesktop
190
Usage_GD_X
191
Usage_GD_Y
192
ReportCount(2)
193
ReportSize(8)
194
Input(Var|Abs)
195
// Byte 4 in report is the wheel
196
Usage_GD_Wheel
197
LogicalMinimum_i8(-1)
198
LogicalMaximum_i8(1)
199
ReportCount(1)
200
ReportSize(8)
201
Input(Var|Rel)
202
// Byte 5 is the button state
203
UsagePage_Button
204
UsageMinimum_i8(0x1)
205
UsageMaximum_i8(0x6)
206
LogicalMinimum_i8(0x1)
207
LogicalMaximum_i8(0x6)
208
ReportCount(1)
209
ReportSize(8)
210
Input(Arr|Abs)
211
)
212
// Make sure we match our original report length
213
FixedSizeVendorReport(PAD_REPORT_LENGTH)
214
)
215
};
216
217
static const __u8 fixed_rdesc_pen[] = {
218
UsagePage_Digitizers
219
Usage_Dig_Pen
220
CollectionApplication(
221
// -- Byte 0 in report
222
ReportId(PEN_REPORT_ID)
223
Usage_Dig_Pen
224
CollectionPhysical(
225
// -- Byte 1 in report
226
Usage_Dig_TipSwitch
227
Usage_Dig_BarrelSwitch
228
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
229
LogicalMinimum_i8(0)
230
LogicalMaximum_i8(1)
231
ReportSize(1)
232
ReportCount(3)
233
Input(Var|Abs)
234
ReportCount(4) // Padding
235
Input(Const)
236
Usage_Dig_InRange
237
ReportCount(1)
238
Input(Var|Abs)
239
ReportSize(16)
240
ReportCount(1)
241
PushPop(
242
UsagePage_GenericDesktop
243
Unit(cm)
244
UnitExponent(-1)
245
PhysicalMinimum_i16(0)
246
PhysicalMaximum_i16(160)
247
LogicalMinimum_i16(0)
248
LogicalMaximum_i16(32767)
249
Usage_GD_X
250
Input(Var|Abs) // Bytes 2+3
251
PhysicalMinimum_i16(0)
252
PhysicalMaximum_i16(100)
253
LogicalMinimum_i16(0)
254
LogicalMaximum_i16(32767)
255
Usage_GD_Y
256
Input(Var|Abs) // Bytes 4+5
257
)
258
UsagePage_Digitizers
259
Usage_Dig_TipPressure
260
LogicalMinimum_i16(0)
261
LogicalMaximum_i16(8191)
262
Input(Var|Abs) // Byte 6+7
263
// Two bytes padding so we don't need to change the report at all
264
ReportSize(8)
265
ReportCount(2)
266
Input(Const) // Byte 6+7
267
)
268
)
269
};
270
271
static const __u8 fixed_rdesc_vendor[] = {
272
UsagePage_Digitizers
273
Usage_Dig_Pen
274
CollectionApplication(
275
// Byte 0
276
// We leave the pen on the vendor report ID
277
ReportId(VENDOR_REPORT_ID)
278
Usage_Dig_Pen
279
CollectionPhysical(
280
// Byte 1 are the buttons
281
LogicalMinimum_i8(0)
282
LogicalMaximum_i8(1)
283
ReportSize(1)
284
Usage_Dig_TipSwitch
285
Usage_Dig_BarrelSwitch
286
Usage_Dig_SecondaryBarrelSwitch
287
ReportCount(3)
288
Input(Var|Abs)
289
ReportCount(4) // Padding
290
Input(Const)
291
Usage_Dig_InRange
292
ReportCount(1)
293
Input(Var|Abs)
294
ReportSize(16)
295
ReportCount(1)
296
PushPop(
297
UsagePage_GenericDesktop
298
Unit(cm)
299
UnitExponent(-1)
300
// Note: reported logical range differs
301
// from the pen report ID for x and y
302
LogicalMinimum_i16(0)
303
LogicalMaximum_i16(32000)
304
PhysicalMinimum_i16(0)
305
PhysicalMaximum_i16(160)
306
// Bytes 2/3 in report
307
Usage_GD_X
308
Input(Var|Abs)
309
LogicalMinimum_i16(0)
310
LogicalMaximum_i16(20000)
311
PhysicalMinimum_i16(0)
312
PhysicalMaximum_i16(100)
313
// Bytes 4/5 in report
314
Usage_GD_Y
315
Input(Var|Abs)
316
)
317
// Bytes 6/7 in report
318
LogicalMinimum_i16(0)
319
LogicalMaximum_i16(8192)
320
Usage_Dig_TipPressure
321
Input(Var|Abs)
322
)
323
)
324
UsagePage_GenericDesktop
325
Usage_GD_Keypad
326
CollectionApplication(
327
// Byte 0
328
ReportId(PAD_REPORT_ID)
329
LogicalMinimum_i8(0)
330
LogicalMaximum_i8(1)
331
UsagePage_Digitizers
332
Usage_Dig_TabletFunctionKeys
333
CollectionPhysical(
334
// Byte 1 are the buttons
335
Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
336
ReportCount(1)
337
ReportSize(1)
338
Input(Var|Abs)
339
ReportCount(7) // Padding
340
Input(Const)
341
// Bytes 2/3 - x/y just exist so we get to be a tablet pad
342
UsagePage_GenericDesktop
343
Usage_GD_X
344
Usage_GD_Y
345
ReportCount(2)
346
ReportSize(8)
347
Input(Var|Abs)
348
// Byte 4 is the button state
349
UsagePage_Button
350
UsageMinimum_i8(0x1)
351
UsageMaximum_i8(0x6)
352
LogicalMinimum_i8(0x0)
353
LogicalMaximum_i8(0x1)
354
ReportCount(6)
355
ReportSize(1)
356
Input(Var|Abs)
357
ReportCount(2)
358
Input(Const)
359
// Byte 5 is the wheel
360
UsagePage_GenericDesktop
361
Usage_GD_Wheel
362
LogicalMinimum_i8(-1)
363
LogicalMaximum_i8(1)
364
ReportCount(1)
365
ReportSize(8)
366
Input(Var|Rel)
367
)
368
// Make sure we match our original report length
369
FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
370
)
371
};
372
373
static const __u8 disabled_rdesc_pen[] = {
374
FixedSizeVendorReport(PEN_REPORT_LENGTH)
375
};
376
377
static const __u8 disabled_rdesc_pad[] = {
378
FixedSizeVendorReport(PAD_REPORT_LENGTH)
379
};
380
381
SEC(HID_BPF_RDESC_FIXUP)
382
int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
383
{
384
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
385
__s32 rdesc_size = hctx->size;
386
__u8 have_fw_id;
387
388
if (!data)
389
return 0; /* EPERM check */
390
391
/* If we have a firmware ID and it matches our expected prefix, we
392
* disable the default pad/pen nodes. They won't send events
393
* but cause duplicate devices.
394
*/
395
have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
396
EXPECTED_FIRMWARE_ID,
397
sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
398
if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
399
if (have_fw_id) {
400
__builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
401
return sizeof(disabled_rdesc_pad);
402
}
403
404
__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
405
return sizeof(fixed_rdesc_pad);
406
}
407
if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {
408
if (have_fw_id) {
409
__builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));
410
return sizeof(disabled_rdesc_pen);
411
}
412
413
__builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));
414
return sizeof(fixed_rdesc_pen);
415
}
416
/* Always fix the vendor mode so the tablet will work even if nothing sets
417
* the udev property (e.g. huion-switcher run manually)
418
*/
419
if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
420
__builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
421
return sizeof(fixed_rdesc_vendor);
422
423
}
424
return 0;
425
}
426
427
SEC(HID_BPF_DEVICE_EVENT)
428
int BPF_PROG(inspiroy_2_fix_events, struct hid_bpf_ctx *hctx)
429
{
430
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
431
432
if (!data)
433
return 0; /* EPERM check */
434
435
/* Only sent if tablet is in default mode */
436
if (data[0] == PAD_REPORT_ID) {
437
/* Nicely enough, this device only supports one button down at a time so
438
* the reports are easy to match. Buttons numbered from the top
439
* Button released: 03 00 00 00 00 00 00 00
440
* Button 1: 03 00 05 00 00 00 00 00 -> b
441
* Button 2: 03 00 0c 00 00 00 00 00 -> i
442
* Button 3: 03 00 08 00 00 00 00 00 -> e
443
* Button 4: 03 01 16 00 00 00 00 00 -> Ctrl S
444
* Button 5: 03 00 2c 00 00 00 00 00 -> space
445
* Button 6: 03 05 1d 00 00 00 00 00 -> Ctrl Alt Z
446
*
447
* Wheel down: 03 01 2d 00 00 00 00 00 -> Ctrl -
448
* Wheel up: 03 01 2e 00 00 00 00 00 -> Ctrl =
449
*/
450
__u8 button = 0;
451
__u8 wheel = 0;
452
453
switch (data[1] << 8 | data[2]) {
454
case 0x0000:
455
break;
456
case 0x0005:
457
button = 1;
458
break;
459
case 0x000c:
460
button = 2;
461
break;
462
case 0x0008:
463
button = 3;
464
break;
465
case 0x0116:
466
button = 4;
467
break;
468
case 0x002c:
469
button = 5;
470
break;
471
case 0x051d:
472
button = 6;
473
break;
474
case 0x012d:
475
wheel = -1;
476
break;
477
case 0x012e:
478
wheel = 1;
479
break;
480
481
}
482
483
__u8 report[6] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, wheel, button};
484
485
__builtin_memcpy(data, report, sizeof(report));
486
return sizeof(report);
487
}
488
489
/* Nothing to do for the PEN_REPORT_ID, it's already mapped */
490
491
/* Only sent if tablet is in raw mode */
492
if (data[0] == VENDOR_REPORT_ID) {
493
/* Pad reports */
494
if (data[1] & 0x20) {
495
/* See fixed_rdesc_pad */
496
struct pad_report {
497
__u8 report_id;
498
__u8 btn_stylus;
499
__u8 x;
500
__u8 y;
501
__u8 buttons;
502
__u8 wheel;
503
} __attribute__((packed)) *pad_report;
504
__u8 wheel = 0;
505
506
/* Wheel report */
507
if (data[1] == 0xf1) {
508
if (data[5] == 2)
509
wheel = 0xff;
510
else
511
wheel = data[5];
512
} else {
513
/* data[4] are the buttons, mapped correctly */
514
last_button_state = data[4];
515
wheel = 0; // wheel
516
}
517
518
pad_report = (struct pad_report *)data;
519
520
pad_report->report_id = PAD_REPORT_ID;
521
pad_report->btn_stylus = 0;
522
pad_report->x = 0;
523
pad_report->y = 0;
524
pad_report->buttons = last_button_state;
525
pad_report->wheel = wheel;
526
527
return sizeof(struct pad_report);
528
} else if (data[1] & 0x80) { /* Pen reports with InRange 1 */
529
__u8 tip_state = data[1] & 0x1;
530
__u8 sec_barrel_state = data[1] & 0x4;
531
532
if (force_tip_down_count > 0) {
533
data[1] |= 0x1;
534
--force_tip_down_count;
535
if (tip_state)
536
force_tip_down_count = 0;
537
}
538
539
/* Tip was down and we just pressed or released the
540
* secondary barrel switch (the physical eraser
541
* button). The device will send up to 4
542
* reports with Tip Switch 0 and sometimes
543
* this report has Tip Switch 0.
544
*/
545
if (last_tip_state &&
546
last_sec_barrel_state != sec_barrel_state) {
547
force_tip_down_count = 4;
548
data[1] |= 0x1;
549
}
550
last_tip_state = tip_state;
551
last_sec_barrel_state = sec_barrel_state;
552
}
553
}
554
555
return 0;
556
}
557
558
HID_BPF_OPS(inspiroy_2) = {
559
.hid_device_event = (void *)inspiroy_2_fix_events,
560
.hid_rdesc_fixup = (void *)hid_fix_rdesc,
561
};
562
563
SEC("syscall")
564
int probe(struct hid_bpf_probe_args *ctx)
565
{
566
switch (ctx->rdesc_size) {
567
case PAD_REPORT_DESCRIPTOR_LENGTH:
568
case PEN_REPORT_DESCRIPTOR_LENGTH:
569
case VENDOR_REPORT_DESCRIPTOR_LENGTH:
570
ctx->retval = 0;
571
break;
572
default:
573
ctx->retval = -EINVAL;
574
}
575
576
return 0;
577
}
578
579
char _license[] SEC("license") = "GPL";
580
581