FILE
Huion__Kamvas-Pro-19.bpf.c
File preview with syntax highlighting.
linux-6.19.14/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright (c) 2024 Benjamin Tissoires 3 */ 4 5#include "vmlinux.h" 6#include "hid_bpf.h" 7#include "hid_bpf_helpers.h" 8#include <bpf/bpf_tracing.h> 9 10#define VID_HUION 0x256C 11#define PID_KAMVAS_PRO_19 0x006B 12#define PID_KAMVAS_PRO_27 0x006c 13#define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902" 14#define NAME_KAMVAS_PRO_27 "HUION Huion Tablet_GT2701" 15 16#define TEST_PREFIX "uhid test " 17 18HID_BPF_CONFIG( 19 HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19), 20 HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_27), 21); 22 23bool prev_was_out_of_range; 24bool in_eraser_mode; 25 26/* 27 * We need to amend the report descriptor for the following: 28 * - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch 29 * - the third button is reported through Invert, and we need some room to report it. 30 * 31 */ 32static const __u8 fixed_rdesc[] = { 33 0x05, 0x0d, // Usage Page (Digitizers) 0 34 0x09, 0x02, // Usage (Pen) 2 35 0xa1, 0x01, // Collection (Application) 4 36 0x85, 0x0a, // Report ID (10) 6 37 0x09, 0x20, // Usage (Stylus) 8 38 0xa1, 0x01, // Collection (Application) 10 39 0x09, 0x42, // Usage (Tip Switch) 12 40 0x09, 0x44, // Usage (Barrel Switch) 14 41 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */ 42 0x09, 0x3c, // Usage (Invert) 18 43 0x09, 0x45, // Usage (Eraser) 20 44 0x15, 0x00, // Logical Minimum (0) 22 45 0x25, 0x01, // Logical Maximum (1) 24 46 0x75, 0x01, // Report Size (1) 26 47 0x95, 0x05, // Report Count (5) 28 /* changed (was 6) */ 48 0x81, 0x02, // Input (Data,Var,Abs) 30 49 0x05, 0x09, // Usage Page (Button) /* inserted */ 50 0x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */ 51 0x95, 0x01, // Report Count (1) /* inserted */ 52 0x81, 0x02, // Input (Data,Var,Abs) /* inserted */ 53 0x05, 0x0d, // Usage Page (Digitizers) /* inserted */ 54 0x09, 0x32, // Usage (In Range) 32 55 0x75, 0x01, // Report Size (1) 34 56 0x95, 0x01, // Report Count (1) 36 57 0x81, 0x02, // Input (Data,Var,Abs) 38 58 0x81, 0x03, // Input (Cnst,Var,Abs) 40 59 0x05, 0x01, // Usage Page (Generic Desktop) 42 60 0x09, 0x30, // Usage (X) 44 61 0x09, 0x31, // Usage (Y) 46 62 0x55, 0x0d, // Unit Exponent (-3) 48 63 0x65, 0x33, // Unit (EnglishLinear: in³) 50 64 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52 65 0x35, 0x00, // Physical Minimum (0) 55 66 0x46, 0x00, 0x08, // Physical Maximum (2048) 57 67 0x75, 0x10, // Report Size (16) 60 68 0x95, 0x02, // Report Count (2) 62 69 0x81, 0x02, // Input (Data,Var,Abs) 64 70 0x05, 0x0d, // Usage Page (Digitizers) 66 71 0x09, 0x30, // Usage (Tip Pressure) 68 72 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70 73 0x75, 0x10, // Report Size (16) 73 74 0x95, 0x01, // Report Count (1) 75 75 0x81, 0x02, // Input (Data,Var,Abs) 77 76 0x09, 0x3d, // Usage (X Tilt) 79 77 0x09, 0x3e, // Usage (Y Tilt) 81 78 0x15, 0xa6, // Logical Minimum (-90) 83 79 0x25, 0x5a, // Logical Maximum (90) 85 80 0x75, 0x08, // Report Size (8) 87 81 0x95, 0x02, // Report Count (2) 89 82 0x81, 0x02, // Input (Data,Var,Abs) 91 83 0xc0, // End Collection 93 84 0xc0, // End Collection 94 85 0x05, 0x0d, // Usage Page (Digitizers) 95 86 0x09, 0x04, // Usage (Touch Screen) 97 87 0xa1, 0x01, // Collection (Application) 99 88 0x85, 0x04, // Report ID (4) 101 89 0x09, 0x22, // Usage (Finger) 103 90 0xa1, 0x02, // Collection (Logical) 105 91 0x05, 0x0d, // Usage Page (Digitizers) 107 92 0x95, 0x01, // Report Count (1) 109 93 0x75, 0x06, // Report Size (6) 111 94 0x09, 0x51, // Usage (Contact Id) 113 95 0x15, 0x00, // Logical Minimum (0) 115 96 0x25, 0x3f, // Logical Maximum (63) 117 97 0x81, 0x02, // Input (Data,Var,Abs) 119 98 0x09, 0x42, // Usage (Tip Switch) 121 99 0x25, 0x01, // Logical Maximum (1) 123 100 0x75, 0x01, // Report Size (1) 125 101 0x95, 0x01, // Report Count (1) 127 102 0x81, 0x02, // Input (Data,Var,Abs) 129 103 0x75, 0x01, // Report Size (1) 131 104 0x95, 0x01, // Report Count (1) 133 105 0x81, 0x03, // Input (Cnst,Var,Abs) 135 106 0x05, 0x01, // Usage Page (Generic Desktop) 137 107 0x75, 0x10, // Report Size (16) 139 108 0x55, 0x0e, // Unit Exponent (-2) 141 109 0x65, 0x11, // Unit (SILinear: cm) 143 110 0x09, 0x30, // Usage (X) 145 111 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147 112 0x35, 0x00, // Physical Minimum (0) 150 113 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152 114 0x81, 0x42, // Input (Data,Var,Abs,Null) 155 115 0x09, 0x31, // Usage (Y) 157 116 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159 117 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162 118 0x81, 0x42, // Input (Data,Var,Abs,Null) 165 119 0x05, 0x0d, // Usage Page (Digitizers) 167 120 0x09, 0x30, // Usage (Tip Pressure) 169 121 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171 122 0x75, 0x10, // Report Size (16) 174 123 0x95, 0x01, // Report Count (1) 176 124 0x81, 0x02, // Input (Data,Var,Abs) 178 125 0xc0, // End Collection 180 126 0x05, 0x0d, // Usage Page (Digitizers) 181 127 0x09, 0x22, // Usage (Finger) 183 128 0xa1, 0x02, // Collection (Logical) 185 129 0x05, 0x0d, // Usage Page (Digitizers) 187 130 0x95, 0x01, // Report Count (1) 189 131 0x75, 0x06, // Report Size (6) 191 132 0x09, 0x51, // Usage (Contact Id) 193 133 0x15, 0x00, // Logical Minimum (0) 195 134 0x25, 0x3f, // Logical Maximum (63) 197 135 0x81, 0x02, // Input (Data,Var,Abs) 199 136 0x09, 0x42, // Usage (Tip Switch) 201 137 0x25, 0x01, // Logical Maximum (1) 203 138 0x75, 0x01, // Report Size (1) 205 139 0x95, 0x01, // Report Count (1) 207 140 0x81, 0x02, // Input (Data,Var,Abs) 209 141 0x75, 0x01, // Report Size (1) 211 142 0x95, 0x01, // Report Count (1) 213 143 0x81, 0x03, // Input (Cnst,Var,Abs) 215 144 0x05, 0x01, // Usage Page (Generic Desktop) 217 145 0x75, 0x10, // Report Size (16) 219 146 0x55, 0x0e, // Unit Exponent (-2) 221 147 0x65, 0x11, // Unit (SILinear: cm) 223 148 0x09, 0x30, // Usage (X) 225 149 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227 150 0x35, 0x00, // Physical Minimum (0) 230 151 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232 152 0x81, 0x42, // Input (Data,Var,Abs,Null) 235 153 0x09, 0x31, // Usage (Y) 237 154 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239 155 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242 156 0x81, 0x42, // Input (Data,Var,Abs,Null) 245 157 0x05, 0x0d, // Usage Page (Digitizers) 247 158 0x09, 0x30, // Usage (Tip Pressure) 249 159 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251 160 0x75, 0x10, // Report Size (16) 254 161 0x95, 0x01, // Report Count (1) 256 162 0x81, 0x02, // Input (Data,Var,Abs) 258 163 0xc0, // End Collection 260 164 0x05, 0x0d, // Usage Page (Digitizers) 261 165 0x09, 0x56, // Usage (Scan Time) 263 166 0x55, 0x00, // Unit Exponent (0) 265 167 0x65, 0x00, // Unit (None) 267 168 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269 169 0x95, 0x01, // Report Count (1) 274 170 0x75, 0x20, // Report Size (32) 276 171 0x81, 0x02, // Input (Data,Var,Abs) 278 172 0x09, 0x54, // Usage (Contact Count) 280 173 0x25, 0x7f, // Logical Maximum (127) 282 174 0x95, 0x01, // Report Count (1) 284 175 0x75, 0x08, // Report Size (8) 286 176 0x81, 0x02, // Input (Data,Var,Abs) 288 177 0x75, 0x08, // Report Size (8) 290 178 0x95, 0x08, // Report Count (8) 292 179 0x81, 0x03, // Input (Cnst,Var,Abs) 294 180 0x85, 0x05, // Report ID (5) 296 181 0x09, 0x55, // Usage (Contact Max) 298 182 0x25, 0x0a, // Logical Maximum (10) 300 183 0x75, 0x08, // Report Size (8) 302 184 0x95, 0x01, // Report Count (1) 304 185 0xb1, 0x02, // Feature (Data,Var,Abs) 306 186 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308 187 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311 188 0x85, 0x06, // Report ID (6) 313 189 0x15, 0x00, // Logical Minimum (0) 315 190 0x26, 0xff, 0x00, // Logical Maximum (255) 317 191 0x75, 0x08, // Report Size (8) 320 192 0x96, 0x00, 0x01, // Report Count (256) 322 193 0xb1, 0x02, // Feature (Data,Var,Abs) 325 194 0xc0, // End Collection 327 195 /* New in Firmware Version: HUION_M220_240524 */ 196 0x05, 0x01, // Usage Page (Generic Desktop) 328 197 0x09, 0x01, // Usage (Pointer) 330 198 0xa1, 0x01, // Collection (Application) 332 199 0x09, 0x01, // Usage (Pointer) 334 200 0xa1, 0x00, // Collection (Physical) 336 201 0x05, 0x09, // Usage Page (Button) 338 202 0x19, 0x01, // UsageMinimum (1) 340 203 0x29, 0x03, // UsageMaximum (3) 342 204 0x15, 0x00, // Logical Minimum (0) 344 205 0x25, 0x01, // Logical Maximum (1) 346 206 0x85, 0x02, // Report ID (2) 348 207 0x95, 0x03, // Report Count (3) 350 208 0x75, 0x01, // Report Size (1) 352 209 0x81, 0x02, // Input (Data,Var,Abs) 354 210 0x95, 0x01, // Report Count (1) 356 211 0x75, 0x05, // Report Size (5) 358 212 0x81, 0x01, // Input (Cnst,Arr,Abs) 360 213 0x05, 0x01, // Usage Page (Generic Desktop) 362 214 0x09, 0x30, // Usage (X) 364 215 0x09, 0x31, // Usage (Y) 366 216 0x15, 0x81, // Logical Minimum (-127) 368 217 0x25, 0x7f, // Logical Maximum (127) 370 218 0x75, 0x08, // Report Size (8) 372 219 0x95, 0x02, // Report Count (2) 374 220 0x81, 0x06, // Input (Data,Var,Rel) 376 221 0x95, 0x04, // Report Count (4) 378 222 0x75, 0x08, // Report Size (8) 380 223 0x81, 0x01, // Input (Cnst,Arr,Abs) 382 224 0xc0, // End Collection 384 225 0xc0, // End Collection 385 226 0x05, 0x0d, // Usage Page (Digitizers) 386 227 0x09, 0x05, // Usage (Touch Pad) 388 228 0xa1, 0x01, // Collection (Application) 390 229 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 392 230 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 395 231 0x15, 0x00, // Logical Minimum (0) 397 232 0x26, 0xff, 0x00, // Logical Maximum (255) 399 233 0x75, 0x08, // Report Size (8) 402 234 0x95, 0x10, // Report Count (16) 404 235 0x85, 0x3f, // Report ID (63) 406 236 0x81, 0x22, // Input (Data,Var,Abs,NoPref) 408 237 0xc0, // End Collection 410 238 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 411 239 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 414 240 0xa1, 0x01, // Collection (Application) 416 241 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 418 242 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 421 243 0x15, 0x00, // Logical Minimum (0) 423 244 0x26, 0xff, 0x00, // Logical Maximum (255) 425 245 0x85, 0x44, // Report ID (68) 428 246 0x75, 0x08, // Report Size (8) 430 247 0x96, 0x6b, 0x05, // Report Count (1387) 432 248 0x81, 0x00, // Input (Data,Arr,Abs) 435 249 0xc0, // End Collection 437 250}; 251 252#define PRE_240524_RDESC_SIZE 328 253#define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */ 254#define FW_240524_RDESC_SIZE 438 255#define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc) 256 257SEC(HID_BPF_RDESC_FIXUP) 258int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx) 259{ 260 __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 261 262 if (!data) 263 return 0; /* EPERM check */ 264 265 if (hctx->size == FW_240524_RDESC_SIZE) { 266 __builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE); 267 return sizeof(fixed_rdesc); 268 } 269 270 __builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE); 271 272 return PRE_240524_RDESC_FIXED_SIZE; 273} 274 275/* 276 * This tablet reports the 3rd button through invert, but this conflict 277 * with the normal eraser mode. 278 * Fortunately, before entering eraser mode, (so Invert = 1), 279 * the tablet always sends an out-of-proximity event. 280 * So we can detect that single event and: 281 * - if there was none but the invert bit was toggled: this is the 282 * third button 283 * - if there was this out-of-proximity event, we are entering 284 * eraser mode, and we will until the next out-of-proximity. 285 */ 286SEC(HID_BPF_DEVICE_EVENT) 287int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx) 288{ 289 __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); 290 291 if (!data) 292 return 0; /* EPERM check */ 293 294 if (data[0] != 0x0a) /* not the pen report ID */ 295 return 0; 296 297 /* stylus is out of range */ 298 if (!(data[1] & 0x40)) { 299 prev_was_out_of_range = true; 300 in_eraser_mode = false; 301 return 0; 302 } 303 304 /* going into eraser mode (Invert = 1) only happens after an 305 * out of range event 306 */ 307 if (prev_was_out_of_range && (data[1] & 0x18)) 308 in_eraser_mode = true; 309 310 /* eraser mode works fine */ 311 if (in_eraser_mode) 312 return 0; 313 314 /* copy the Invert bit reported for the 3rd button in bit 7 */ 315 if (data[1] & 0x08) 316 data[1] |= 0x20; 317 318 /* clear Invert bit now that it was copied */ 319 data[1] &= 0xf7; 320 321 prev_was_out_of_range = false; 322 323 return 0; 324} 325 326HID_BPF_OPS(huion_Kamvas_pro_19) = { 327 .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas_pro_19, 328 .hid_device_event = (void *)kamvas_pro_19_fix_3rd_button, 329}; 330 331SEC("syscall") 332int probe(struct hid_bpf_probe_args *ctx) 333{ 334 335 ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) || 336 (ctx->rdesc_size == FW_240524_RDESC_SIZE)); 337 if (ctx->retval) 338 ctx->retval = -EINVAL; 339 340 /* ensure the kernel isn't fixed already */ 341 if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */ 342 ctx->retval = -EINVAL; 343 344 struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid); 345 346 if (!hctx) { 347 return ctx->retval = -EINVAL; 348 return 0; 349 } 350 351 const char *name = hctx->hid->name; 352 353 /* strip out TEST_PREFIX */ 354 if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1)) 355 name += sizeof(TEST_PREFIX) - 1; 356 357 if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)) && 358 __builtin_memcmp(name, NAME_KAMVAS_PRO_27, sizeof(NAME_KAMVAS_PRO_27))) 359 ctx->retval = -EINVAL; 360 361 hid_bpf_release_context(hctx); 362 363 return 0; 364} 365 366char _license[] SEC("license") = "GPL";
~/
Read-only file preview.