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 14 HID_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 180 static 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 223 SEC(HID_BPF_RDESC_FIXUP) 224 int 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 253 SEC(HID_BPF_DEVICE_EVENT) 254 int 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 285 HID_BPF_OPS(xppen_deco01v3) = { 286 .hid_rdesc_fixup = (void *)xppen_deco01v3_rdesc_fixup, 287 .hid_device_event = (void *)xppen_deco01v3_device_event, 288 }; 289 290 SEC("syscall") 291 int 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 305 char _license[] SEC("license") = "GPL"; 306