Path: blob/master/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
53491 views
// SPDX-License-Identifier: GPL-2.0-only1/* Copyright (c) 2024 Benjamin Tissoires2*/34#include "vmlinux.h"5#include "hid_bpf.h"6#include "hid_bpf_helpers.h"7#include <bpf/bpf_tracing.h>89#define VID_HUION 0x256C10#define PID_KAMVAS_PRO_19 0x006B11#define PID_KAMVAS_PRO_27 0x006c12#define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902"13#define NAME_KAMVAS_PRO_27 "HUION Huion Tablet_GT2701"1415#define TEST_PREFIX "uhid test "1617HID_BPF_CONFIG(18HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19),19HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_27),20);2122bool prev_was_out_of_range;23bool in_eraser_mode;2425/*26* We need to amend the report descriptor for the following:27* - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch28* - the third button is reported through Invert, and we need some room to report it.29*30*/31static const __u8 fixed_rdesc[] = {320x05, 0x0d, // Usage Page (Digitizers) 0330x09, 0x02, // Usage (Pen) 2340xa1, 0x01, // Collection (Application) 4350x85, 0x0a, // Report ID (10) 6360x09, 0x20, // Usage (Stylus) 8370xa1, 0x01, // Collection (Application) 10380x09, 0x42, // Usage (Tip Switch) 12390x09, 0x44, // Usage (Barrel Switch) 14400x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */410x09, 0x3c, // Usage (Invert) 18420x09, 0x45, // Usage (Eraser) 20430x15, 0x00, // Logical Minimum (0) 22440x25, 0x01, // Logical Maximum (1) 24450x75, 0x01, // Report Size (1) 26460x95, 0x05, // Report Count (5) 28 /* changed (was 6) */470x81, 0x02, // Input (Data,Var,Abs) 30480x05, 0x09, // Usage Page (Button) /* inserted */490x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */500x95, 0x01, // Report Count (1) /* inserted */510x81, 0x02, // Input (Data,Var,Abs) /* inserted */520x05, 0x0d, // Usage Page (Digitizers) /* inserted */530x09, 0x32, // Usage (In Range) 32540x75, 0x01, // Report Size (1) 34550x95, 0x01, // Report Count (1) 36560x81, 0x02, // Input (Data,Var,Abs) 38570x81, 0x03, // Input (Cnst,Var,Abs) 40580x05, 0x01, // Usage Page (Generic Desktop) 42590x09, 0x30, // Usage (X) 44600x09, 0x31, // Usage (Y) 46610x55, 0x0d, // Unit Exponent (-3) 48620x65, 0x33, // Unit (EnglishLinear: in³) 50630x26, 0xff, 0x7f, // Logical Maximum (32767) 52640x35, 0x00, // Physical Minimum (0) 55650x46, 0x00, 0x08, // Physical Maximum (2048) 57660x75, 0x10, // Report Size (16) 60670x95, 0x02, // Report Count (2) 62680x81, 0x02, // Input (Data,Var,Abs) 64690x05, 0x0d, // Usage Page (Digitizers) 66700x09, 0x30, // Usage (Tip Pressure) 68710x26, 0xff, 0x3f, // Logical Maximum (16383) 70720x75, 0x10, // Report Size (16) 73730x95, 0x01, // Report Count (1) 75740x81, 0x02, // Input (Data,Var,Abs) 77750x09, 0x3d, // Usage (X Tilt) 79760x09, 0x3e, // Usage (Y Tilt) 81770x15, 0xa6, // Logical Minimum (-90) 83780x25, 0x5a, // Logical Maximum (90) 85790x75, 0x08, // Report Size (8) 87800x95, 0x02, // Report Count (2) 89810x81, 0x02, // Input (Data,Var,Abs) 91820xc0, // End Collection 93830xc0, // End Collection 94840x05, 0x0d, // Usage Page (Digitizers) 95850x09, 0x04, // Usage (Touch Screen) 97860xa1, 0x01, // Collection (Application) 99870x85, 0x04, // Report ID (4) 101880x09, 0x22, // Usage (Finger) 103890xa1, 0x02, // Collection (Logical) 105900x05, 0x0d, // Usage Page (Digitizers) 107910x95, 0x01, // Report Count (1) 109920x75, 0x06, // Report Size (6) 111930x09, 0x51, // Usage (Contact Id) 113940x15, 0x00, // Logical Minimum (0) 115950x25, 0x3f, // Logical Maximum (63) 117960x81, 0x02, // Input (Data,Var,Abs) 119970x09, 0x42, // Usage (Tip Switch) 121980x25, 0x01, // Logical Maximum (1) 123990x75, 0x01, // Report Size (1) 1251000x95, 0x01, // Report Count (1) 1271010x81, 0x02, // Input (Data,Var,Abs) 1291020x75, 0x01, // Report Size (1) 1311030x95, 0x01, // Report Count (1) 1331040x81, 0x03, // Input (Cnst,Var,Abs) 1351050x05, 0x01, // Usage Page (Generic Desktop) 1371060x75, 0x10, // Report Size (16) 1391070x55, 0x0e, // Unit Exponent (-2) 1411080x65, 0x11, // Unit (SILinear: cm) 1431090x09, 0x30, // Usage (X) 1451100x26, 0xff, 0x7f, // Logical Maximum (32767) 1471110x35, 0x00, // Physical Minimum (0) 1501120x46, 0x15, 0x0c, // Physical Maximum (3093) 1521130x81, 0x42, // Input (Data,Var,Abs,Null) 1551140x09, 0x31, // Usage (Y) 1571150x26, 0xff, 0x7f, // Logical Maximum (32767) 1591160x46, 0xcb, 0x06, // Physical Maximum (1739) 1621170x81, 0x42, // Input (Data,Var,Abs,Null) 1651180x05, 0x0d, // Usage Page (Digitizers) 1671190x09, 0x30, // Usage (Tip Pressure) 1691200x26, 0xff, 0x1f, // Logical Maximum (8191) 1711210x75, 0x10, // Report Size (16) 1741220x95, 0x01, // Report Count (1) 1761230x81, 0x02, // Input (Data,Var,Abs) 1781240xc0, // End Collection 1801250x05, 0x0d, // Usage Page (Digitizers) 1811260x09, 0x22, // Usage (Finger) 1831270xa1, 0x02, // Collection (Logical) 1851280x05, 0x0d, // Usage Page (Digitizers) 1871290x95, 0x01, // Report Count (1) 1891300x75, 0x06, // Report Size (6) 1911310x09, 0x51, // Usage (Contact Id) 1931320x15, 0x00, // Logical Minimum (0) 1951330x25, 0x3f, // Logical Maximum (63) 1971340x81, 0x02, // Input (Data,Var,Abs) 1991350x09, 0x42, // Usage (Tip Switch) 2011360x25, 0x01, // Logical Maximum (1) 2031370x75, 0x01, // Report Size (1) 2051380x95, 0x01, // Report Count (1) 2071390x81, 0x02, // Input (Data,Var,Abs) 2091400x75, 0x01, // Report Size (1) 2111410x95, 0x01, // Report Count (1) 2131420x81, 0x03, // Input (Cnst,Var,Abs) 2151430x05, 0x01, // Usage Page (Generic Desktop) 2171440x75, 0x10, // Report Size (16) 2191450x55, 0x0e, // Unit Exponent (-2) 2211460x65, 0x11, // Unit (SILinear: cm) 2231470x09, 0x30, // Usage (X) 2251480x26, 0xff, 0x7f, // Logical Maximum (32767) 2271490x35, 0x00, // Physical Minimum (0) 2301500x46, 0x15, 0x0c, // Physical Maximum (3093) 2321510x81, 0x42, // Input (Data,Var,Abs,Null) 2351520x09, 0x31, // Usage (Y) 2371530x26, 0xff, 0x7f, // Logical Maximum (32767) 2391540x46, 0xcb, 0x06, // Physical Maximum (1739) 2421550x81, 0x42, // Input (Data,Var,Abs,Null) 2451560x05, 0x0d, // Usage Page (Digitizers) 2471570x09, 0x30, // Usage (Tip Pressure) 2491580x26, 0xff, 0x1f, // Logical Maximum (8191) 2511590x75, 0x10, // Report Size (16) 2541600x95, 0x01, // Report Count (1) 2561610x81, 0x02, // Input (Data,Var,Abs) 2581620xc0, // End Collection 2601630x05, 0x0d, // Usage Page (Digitizers) 2611640x09, 0x56, // Usage (Scan Time) 2631650x55, 0x00, // Unit Exponent (0) 2651660x65, 0x00, // Unit (None) 2671670x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 2691680x95, 0x01, // Report Count (1) 2741690x75, 0x20, // Report Size (32) 2761700x81, 0x02, // Input (Data,Var,Abs) 2781710x09, 0x54, // Usage (Contact Count) 2801720x25, 0x7f, // Logical Maximum (127) 2821730x95, 0x01, // Report Count (1) 2841740x75, 0x08, // Report Size (8) 2861750x81, 0x02, // Input (Data,Var,Abs) 2881760x75, 0x08, // Report Size (8) 2901770x95, 0x08, // Report Count (8) 2921780x81, 0x03, // Input (Cnst,Var,Abs) 2941790x85, 0x05, // Report ID (5) 2961800x09, 0x55, // Usage (Contact Max) 2981810x25, 0x0a, // Logical Maximum (10) 3001820x75, 0x08, // Report Size (8) 3021830x95, 0x01, // Report Count (1) 3041840xb1, 0x02, // Feature (Data,Var,Abs) 3061850x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 3081860x09, 0xc5, // Usage (Vendor Usage 0xc5) 3111870x85, 0x06, // Report ID (6) 3131880x15, 0x00, // Logical Minimum (0) 3151890x26, 0xff, 0x00, // Logical Maximum (255) 3171900x75, 0x08, // Report Size (8) 3201910x96, 0x00, 0x01, // Report Count (256) 3221920xb1, 0x02, // Feature (Data,Var,Abs) 3251930xc0, // End Collection 327194/* New in Firmware Version: HUION_M220_240524 */1950x05, 0x01, // Usage Page (Generic Desktop) 3281960x09, 0x01, // Usage (Pointer) 3301970xa1, 0x01, // Collection (Application) 3321980x09, 0x01, // Usage (Pointer) 3341990xa1, 0x00, // Collection (Physical) 3362000x05, 0x09, // Usage Page (Button) 3382010x19, 0x01, // UsageMinimum (1) 3402020x29, 0x03, // UsageMaximum (3) 3422030x15, 0x00, // Logical Minimum (0) 3442040x25, 0x01, // Logical Maximum (1) 3462050x85, 0x02, // Report ID (2) 3482060x95, 0x03, // Report Count (3) 3502070x75, 0x01, // Report Size (1) 3522080x81, 0x02, // Input (Data,Var,Abs) 3542090x95, 0x01, // Report Count (1) 3562100x75, 0x05, // Report Size (5) 3582110x81, 0x01, // Input (Cnst,Arr,Abs) 3602120x05, 0x01, // Usage Page (Generic Desktop) 3622130x09, 0x30, // Usage (X) 3642140x09, 0x31, // Usage (Y) 3662150x15, 0x81, // Logical Minimum (-127) 3682160x25, 0x7f, // Logical Maximum (127) 3702170x75, 0x08, // Report Size (8) 3722180x95, 0x02, // Report Count (2) 3742190x81, 0x06, // Input (Data,Var,Rel) 3762200x95, 0x04, // Report Count (4) 3782210x75, 0x08, // Report Size (8) 3802220x81, 0x01, // Input (Cnst,Arr,Abs) 3822230xc0, // End Collection 3842240xc0, // End Collection 3852250x05, 0x0d, // Usage Page (Digitizers) 3862260x09, 0x05, // Usage (Touch Pad) 3882270xa1, 0x01, // Collection (Application) 3902280x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 3922290x09, 0x0c, // Usage (Vendor Usage 0x0c) 3952300x15, 0x00, // Logical Minimum (0) 3972310x26, 0xff, 0x00, // Logical Maximum (255) 3992320x75, 0x08, // Report Size (8) 4022330x95, 0x10, // Report Count (16) 4042340x85, 0x3f, // Report ID (63) 4062350x81, 0x22, // Input (Data,Var,Abs,NoPref) 4082360xc0, // End Collection 4102370x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 4112380x09, 0x0c, // Usage (Vendor Usage 0x0c) 4142390xa1, 0x01, // Collection (Application) 4162400x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 4182410x09, 0x0c, // Usage (Vendor Usage 0x0c) 4212420x15, 0x00, // Logical Minimum (0) 4232430x26, 0xff, 0x00, // Logical Maximum (255) 4252440x85, 0x44, // Report ID (68) 4282450x75, 0x08, // Report Size (8) 4302460x96, 0x6b, 0x05, // Report Count (1387) 4322470x81, 0x00, // Input (Data,Arr,Abs) 4352480xc0, // End Collection 437249};250251#define PRE_240524_RDESC_SIZE 328252#define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */253#define FW_240524_RDESC_SIZE 438254#define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc)255256SEC(HID_BPF_RDESC_FIXUP)257int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx)258{259__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);260261if (!data)262return 0; /* EPERM check */263264if (hctx->size == FW_240524_RDESC_SIZE) {265__builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE);266return sizeof(fixed_rdesc);267}268269__builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE);270271return PRE_240524_RDESC_FIXED_SIZE;272}273274/*275* This tablet reports the 3rd button through invert, but this conflict276* with the normal eraser mode.277* Fortunately, before entering eraser mode, (so Invert = 1),278* the tablet always sends an out-of-proximity event.279* So we can detect that single event and:280* - if there was none but the invert bit was toggled: this is the281* third button282* - if there was this out-of-proximity event, we are entering283* eraser mode, and we will until the next out-of-proximity.284*/285SEC(HID_BPF_DEVICE_EVENT)286int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx)287{288__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);289290if (!data)291return 0; /* EPERM check */292293if (data[0] != 0x0a) /* not the pen report ID */294return 0;295296/* stylus is out of range */297if (!(data[1] & 0x40)) {298prev_was_out_of_range = true;299in_eraser_mode = false;300return 0;301}302303/* going into eraser mode (Invert = 1) only happens after an304* out of range event305*/306if (prev_was_out_of_range && (data[1] & 0x18))307in_eraser_mode = true;308309/* eraser mode works fine */310if (in_eraser_mode)311return 0;312313/* copy the Invert bit reported for the 3rd button in bit 7 */314if (data[1] & 0x08)315data[1] |= 0x20;316317/* clear Invert bit now that it was copied */318data[1] &= 0xf7;319320prev_was_out_of_range = false;321322return 0;323}324325HID_BPF_OPS(huion_Kamvas_pro_19) = {326.hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas_pro_19,327.hid_device_event = (void *)kamvas_pro_19_fix_3rd_button,328};329330SEC("syscall")331int probe(struct hid_bpf_probe_args *ctx)332{333334ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) ||335(ctx->rdesc_size == FW_240524_RDESC_SIZE));336if (ctx->retval)337ctx->retval = -EINVAL;338339/* ensure the kernel isn't fixed already */340if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */341ctx->retval = -EINVAL;342343struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid);344345if (!hctx) {346return ctx->retval = -EINVAL;347return 0;348}349350const char *name = hctx->hid->name;351352/* strip out TEST_PREFIX */353if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1))354name += sizeof(TEST_PREFIX) - 1;355356if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)) &&357__builtin_memcmp(name, NAME_KAMVAS_PRO_27, sizeof(NAME_KAMVAS_PRO_27)))358ctx->retval = -EINVAL;359360hid_bpf_release_context(hctx);361362return 0;363}364365char _license[] SEC("license") = "GPL";366367368