File Index
Files and directories
Sign in
FILE

XPPen__Deco01V3.bpf.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright (c) 2025 Red Hat
  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_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */
 12#define PID_DECO_01_V3 0x0947
 13
 14HID_BPF_CONFIG(
 15	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_01_V3),
 16);
 17
 18/*
 19 * Default report descriptor reports:
 20 * - a report descriptor for the pad buttons, reported as key sequences
 21 * - a report descriptor for the pen
 22 * - a vendor-specific report descriptor
 23 *
 24 * The Pad report descriptor, see
 25 * https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/issues/54
 26 *
 27 * # Report descriptor length: 102 bytes
 28 * 0x05, 0x01,                    // Usage Page (Generic Desktop)              0
 29 * 0x09, 0x02,                    // Usage (Mouse)                             2
 30 * 0xa1, 0x01,                    // Collection (Application)                  4
 31 * 0x85, 0x09,                    //   Report ID (9)                           6
 32 * 0x09, 0x01,                    //   Usage (Pointer)                         8
 33 * 0xa1, 0x00,                    //   Collection (Physical)                   10
 34 * 0x05, 0x09,                    //     Usage Page (Button)                   12
 35 * 0x19, 0x01,                    //     UsageMinimum (1)                      14
 36 * 0x29, 0x03,                    //     UsageMaximum (3)                      16
 37 * 0x15, 0x00,                    //     Logical Minimum (0)                   18
 38 * 0x25, 0x01,                    //     Logical Maximum (1)                   20
 39 * 0x95, 0x03,                    //     Report Count (3)                      22
 40 * 0x75, 0x01,                    //     Report Size (1)                       24
 41 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  26
 42 * 0x95, 0x05,                    //     Report Count (5)                      28
 43 * 0x81, 0x01,                    //     Input (Cnst,Arr,Abs)                  30
 44 * 0x05, 0x01,                    //     Usage Page (Generic Desktop)          32
 45 * 0x09, 0x30,                    //     Usage (X)                             34
 46 * 0x09, 0x31,                    //     Usage (Y)                             36
 47 * 0x26, 0xff, 0x7f,              //     Logical Maximum (32767)               38
 48 * 0x95, 0x02,                    //     Report Count (2)                      41
 49 * 0x75, 0x10,                    //     Report Size (16)                      43
 50 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  45
 51 * 0x05, 0x0d,                    //     Usage Page (Digitizers)               47
 52 * 0x09, 0x30,                    //     Usage (Tip Pressure)                  49
 53 * 0x26, 0xff, 0x07,              //     Logical Maximum (2047)                51
 54 * 0x95, 0x01,                    //     Report Count (1)                      54
 55 * 0x75, 0x10,                    //     Report Size (16)                      56
 56 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  58
 57 * 0xc0,                          //   End Collection                          60
 58 * 0xc0,                          // End Collection                            61
 59 * 0x05, 0x01,                    // Usage Page (Generic Desktop)              62
 60 * 0x09, 0x06,                    // Usage (Keyboard)                          64
 61 * 0xa1, 0x01,                    // Collection (Application)                  66
 62 * 0x85, 0x06,                    //   Report ID (6)                           68
 63 * 0x05, 0x07,                    //   Usage Page (Keyboard/Keypad)            70
 64 * 0x19, 0xe0,                    //   UsageMinimum (224)                      72
 65 * 0x29, 0xe7,                    //   UsageMaximum (231)                      74
 66 * 0x15, 0x00,                    //   Logical Minimum (0)                     76
 67 * 0x25, 0x01,                    //   Logical Maximum (1)                     78
 68 * 0x75, 0x01,                    //   Report Size (1)                         80
 69 * 0x95, 0x08,                    //   Report Count (8)                        82
 70 * 0x81, 0x02,                    //   Input (Data,Var,Abs)                    84
 71 * 0x05, 0x07,                    //   Usage Page (Keyboard/Keypad)            86
 72 * 0x19, 0x00,                    //   UsageMinimum (0)                        88
 73 * 0x29, 0xff,                    //   UsageMaximum (255)                      90
 74 * 0x26, 0xff, 0x00,              //   Logical Maximum (255)                   92
 75 * 0x75, 0x08,                    //   Report Size (8)                         95
 76 * 0x95, 0x06,                    //   Report Count (6)                        97
 77 * 0x81, 0x00,                    //   Input (Data,Arr,Abs)                    99
 78 * 0xc0,                          // End Collection                            101
 79 *
 80 * And key events for buttons top->bottom are:
 81 * Buttons released: 06 00 00 00 00 00 00 00
 82 * Button1:          06 00 05 00 00 00 00 00 -> b
 83 * Button2:          06 00 08 00 00 00 00 00 -> e
 84 * Button3:          06 04 00 00 00 00 00 00 -> LAlt
 85 * Button4:          06 00 2c 00 00 00 00 00 -> Space
 86 * Button5:          06 01 16 00 00 00 00 00 -> LControl + s
 87 * Button6:          06 01 1d 00 00 00 00 00 -> LControl + z
 88 * Button7:          06 01 57 00 00 00 00 00 -> LControl + Keypad Plus
 89 * Button8:          06 01 56 00 00 00 00 00 -> LControl + Keypad Dash
 90 *
 91 * When multiple buttons are pressed at the same time, the values used to
 92 * identify the buttons are identical, but they appear in different bytes of the
 93 * record. For example, when button 2 (0x08) and button 1 (0x05) are pressed,
 94 * this is the report:
 95 *
 96 *   Buttons 2 and 1:  06 00 08 05 00 00 00 00 -> e + b
 97 *
 98 * Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the
 99 * report.
100 *
101 * Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 3
102 * and 5 generates this report:
103 *
104 *   Buttons 3 and 5:  06 05 16 00 00 00 00 00 -> LControl + LAlt + s
105 *                        -- --
106 *                         |  |
107 *                         |  `- Button 5 (0x16)
108 *                         `- 0x05 = 0101. Button 3 is pressed
109 *                                    ^
110 *
111 * pad_buttons contains a list of buttons that can be matched in
112 * HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit.
113 *
114 *
115 * The Pen report descriptor announces a wrong tilt range:
116 *
117 * Report descriptor length: 109 bytes
118 * 0x05, 0x0d,                    // Usage Page (Digitizers)                   0
119 * 0x09, 0x02,                    // Usage (Pen)                               2
120 * 0xa1, 0x01,                    // Collection (Application)                  4
121 * 0x85, 0x07,                    //   Report ID (7)                           6
122 * 0x09, 0x20,                    //   Usage (Stylus)                          8
123 * 0xa1, 0x01,                    //   Collection (Application)                10
124 * 0x09, 0x42,                    //     Usage (Tip Switch)                    12
125 * 0x09, 0x44,                    //     Usage (Barrel Switch)                 14
126 * 0x09, 0x45,                    //     Usage (Eraser)                        16
127 * 0x09, 0x3c,                    //     Usage (Invert)                        18
128 * 0x15, 0x00,                    //     Logical Minimum (0)                   20
129 * 0x25, 0x01,                    //     Logical Maximum (1)                   22
130 * 0x75, 0x01,                    //     Report Size (1)                       24
131 * 0x95, 0x04,                    //     Report Count (4)                      26
132 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  28
133 * 0x95, 0x01,                    //     Report Count (1)                      30
134 * 0x81, 0x03,                    //     Input (Cnst,Var,Abs)                  32
135 * 0x09, 0x32,                    //     Usage (In Range)                      34
136 * 0x95, 0x01,                    //     Report Count (1)                      36
137 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  38
138 * 0x95, 0x02,                    //     Report Count (2)                      40
139 * 0x81, 0x03,                    //     Input (Cnst,Var,Abs)                  42
140 * 0x75, 0x10,                    //     Report Size (16)                      44
141 * 0x95, 0x01,                    //     Report Count (1)                      46
142 * 0x35, 0x00,                    //     Physical Minimum (0)                  48
143 * 0xa4,                          //     Push                                  50
144 * 0x05, 0x01,                    //     Usage Page (Generic Desktop)          51
145 * 0x09, 0x30,                    //     Usage (X)                             53
146 * 0x65, 0x13,                    //     Unit (EnglishLinear: in)              55
147 * 0x55, 0x0d,                    //     Unit Exponent (-3)                    57
148 * 0x46, 0x10, 0x27,              //     Physical Maximum (10000)              59
149 * 0x26, 0xff, 0x7f,              //     Logical Maximum (32767)               62
150 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  65
151 * 0x09, 0x31,                    //     Usage (Y)                             67
152 * 0x46, 0x6a, 0x18,              //     Physical Maximum (6250)               69
153 * 0x26, 0xff, 0x7f,              //     Logical Maximum (32767)               72
154 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  75
155 * 0xb4,                          //     Pop                                   77
156 * 0x09, 0x30,                    //     Usage (X)                             78
157 * 0x45, 0x00,                    //     Physical Maximum (0)                  80
158 * 0x26, 0xff, 0x3f,              //     Logical Maximum (16383)               82
159 * 0x81, 0x42,                    //     Input (Data,Var,Abs,Null)             85
160 * 0x09, 0x3d,                    //     Usage (Start)                         87
161 * 0x15, 0x81,                    //     Logical Minimum (-127)                89  <- Change from -127 to -60
162 * 0x25, 0x7f,                    //     Logical Maximum (127)                 91  <- Change from 127 to 60
163 * 0x75, 0x08,                    //     Report Size (8)                       93
164 * 0x95, 0x01,                    //     Report Count (1)                      95
165 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  97
166 * 0x09, 0x3e,                    //     Usage (Select)                        99
167 * 0x15, 0x81,                    //     Logical Minimum (-127)                101  <- Change from -127 to -60
168 * 0x25, 0x7f,                    //     Logical Maximum (127)                 103  <- Change from 127 to 60
169 * 0x81, 0x02,                    //     Input (Data,Var,Abs)                  105
170 * 0xc0,                          //   End Collection                          107
171 * 0xc0,                          // End Collection                            108
172 */
173
174#define PEN_REPORT_DESCRIPTOR_LENGTH 109
175#define PAD_REPORT_DESCRIPTOR_LENGTH 102
176#define PAD_REPORT_LENGTH 8
177#define PAD_REPORT_ID 6
178#define PAD_NUM_BUTTONS 8
179
180static const __u8 fixed_rdesc_pad[] = {
181	UsagePage_GenericDesktop
182	Usage_GD_Keypad
183	CollectionApplication(
184		// Byte 0 in report is the report ID
185		ReportId(PAD_REPORT_ID)
186		ReportCount(1)
187		ReportSize(8)
188		UsagePage_Digitizers
189		Usage_Dig_TabletFunctionKeys
190		CollectionPhysical(
191			// Byte 1 is the button state
192			UsagePage_Button
193			UsageMinimum_i8(0x01)
194			UsageMaximum_i8(PAD_NUM_BUTTONS)
195			LogicalMinimum_i8(0x0)
196			LogicalMaximum_i8(0x1)
197			ReportCount(PAD_NUM_BUTTONS)
198			ReportSize(1)
199			Input(Var|Abs)
200			// Byte 2 in report - just exists so we get to be a tablet pad
201			UsagePage_Digitizers
202			Usage_Dig_BarrelSwitch // BTN_STYLUS
203			ReportCount(1)
204			ReportSize(1)
205			Input(Var|Abs)
206			ReportCount(7) // padding
207			Input(Const)
208			// Bytes 3/4 in report - just exists so we get to be a tablet pad
209			UsagePage_GenericDesktop
210			Usage_GD_X
211			Usage_GD_Y
212			ReportCount(2)
213			ReportSize(8)
214			Input(Var|Abs)
215			// Byte 5-7 are padding so we match the original report lengtth
216			ReportCount(3)
217			ReportSize(8)
218			Input(Const)
219		)
220	)
221};
222
223SEC(HID_BPF_RDESC_FIXUP)
224int BPF_PROG(xppen_deco01v3_rdesc_fixup, struct hid_bpf_ctx *hctx)
225{
226	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
227
228	const __u8 wrong_logical_range[] = {0x15, 0x81, 0x25, 0x7f};
229	const __u8 correct_logical_range[] = {0x15, 0xc4, 0x25, 0x3c};
230
231	if (!data)
232		return 0; /* EPERM check */
233
234	switch (hctx->size) {
235	case PAD_REPORT_DESCRIPTOR_LENGTH:
236		__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
237		return sizeof(fixed_rdesc_pad);
238	case PEN_REPORT_DESCRIPTOR_LENGTH:
239		if (__builtin_memcmp(&data[89], wrong_logical_range,
240				     sizeof(wrong_logical_range)) == 0)
241			__builtin_memcpy(&data[89], correct_logical_range,
242					 sizeof(correct_logical_range));
243		if (__builtin_memcmp(&data[101], wrong_logical_range,
244				     sizeof(wrong_logical_range)) == 0)
245			__builtin_memcpy(&data[101], correct_logical_range,
246					 sizeof(correct_logical_range));
247		break;
248	}
249
250	return 0;
251}
252
253SEC(HID_BPF_DEVICE_EVENT)
254int BPF_PROG(xppen_deco01v3_device_event, struct hid_bpf_ctx *hctx)
255{
256	static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2c, 0x16, 0x1d, 0x57, 0x56 };
257	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PAD_REPORT_LENGTH /* size */);
258
259	if (!data)
260		return 0; /* EPERM check */
261
262	if (data[0] == PAD_REPORT_ID) {
263		__u8 button_mask = 0;
264		size_t d, b;
265
266		/* data[1] stores the status of BTN_2 in the 3rd bit*/
267		if (data[1] & BIT(2))
268			button_mask |= BIT(2);
269
270		/* The rest of the descriptor stores the buttons as in pad_buttons */
271		for (d = 2; d < 8; d++) {
272			for (b = 0; b < sizeof(pad_buttons); b++) {
273				if (data[d] != 0 && data[d] == pad_buttons[b])
274					button_mask |= BIT(b);
275			}
276		}
277
278		__u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00};
279
280		__builtin_memcpy(data, report, sizeof(report));
281	}
282	return 0;
283}
284
285HID_BPF_OPS(xppen_deco01v3) = {
286	.hid_rdesc_fixup = (void *)xppen_deco01v3_rdesc_fixup,
287	.hid_device_event = (void *)xppen_deco01v3_device_event,
288};
289
290SEC("syscall")
291int probe(struct hid_bpf_probe_args *ctx)
292{
293	switch (ctx->rdesc_size) {
294	case PAD_REPORT_DESCRIPTOR_LENGTH:
295	case PEN_REPORT_DESCRIPTOR_LENGTH:
296		ctx->retval = 0;
297		break;
298	default:
299		ctx->retval = -EINVAL;
300	}
301
302	return 0;
303}
304
305char _license[] SEC("license") = "GPL";
~/ Read-only file preview.