Path: blob/master/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
26285 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 NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902"1213#define TEST_PREFIX "uhid test "1415HID_BPF_CONFIG(16HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19),17);1819bool prev_was_out_of_range;20bool in_eraser_mode;2122/*23* We need to amend the report descriptor for the following:24* - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch25* - the third button is reported through Invert, and we need some room to report it.26*27*/28static const __u8 fixed_rdesc[] = {290x05, 0x0d, // Usage Page (Digitizers) 0300x09, 0x02, // Usage (Pen) 2310xa1, 0x01, // Collection (Application) 4320x85, 0x0a, // Report ID (10) 6330x09, 0x20, // Usage (Stylus) 8340xa1, 0x01, // Collection (Application) 10350x09, 0x42, // Usage (Tip Switch) 12360x09, 0x44, // Usage (Barrel Switch) 14370x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */380x09, 0x3c, // Usage (Invert) 18390x09, 0x45, // Usage (Eraser) 20400x15, 0x00, // Logical Minimum (0) 22410x25, 0x01, // Logical Maximum (1) 24420x75, 0x01, // Report Size (1) 26430x95, 0x05, // Report Count (5) 28 /* changed (was 6) */440x81, 0x02, // Input (Data,Var,Abs) 30450x05, 0x09, // Usage Page (Button) /* inserted */460x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */470x95, 0x01, // Report Count (1) /* inserted */480x81, 0x02, // Input (Data,Var,Abs) /* inserted */490x05, 0x0d, // Usage Page (Digitizers) /* inserted */500x09, 0x32, // Usage (In Range) 32510x75, 0x01, // Report Size (1) 34520x95, 0x01, // Report Count (1) 36530x81, 0x02, // Input (Data,Var,Abs) 38540x81, 0x03, // Input (Cnst,Var,Abs) 40550x05, 0x01, // Usage Page (Generic Desktop) 42560x09, 0x30, // Usage (X) 44570x09, 0x31, // Usage (Y) 46580x55, 0x0d, // Unit Exponent (-3) 48590x65, 0x33, // Unit (EnglishLinear: in³) 50600x26, 0xff, 0x7f, // Logical Maximum (32767) 52610x35, 0x00, // Physical Minimum (0) 55620x46, 0x00, 0x08, // Physical Maximum (2048) 57630x75, 0x10, // Report Size (16) 60640x95, 0x02, // Report Count (2) 62650x81, 0x02, // Input (Data,Var,Abs) 64660x05, 0x0d, // Usage Page (Digitizers) 66670x09, 0x30, // Usage (Tip Pressure) 68680x26, 0xff, 0x3f, // Logical Maximum (16383) 70690x75, 0x10, // Report Size (16) 73700x95, 0x01, // Report Count (1) 75710x81, 0x02, // Input (Data,Var,Abs) 77720x09, 0x3d, // Usage (X Tilt) 79730x09, 0x3e, // Usage (Y Tilt) 81740x15, 0xa6, // Logical Minimum (-90) 83750x25, 0x5a, // Logical Maximum (90) 85760x75, 0x08, // Report Size (8) 87770x95, 0x02, // Report Count (2) 89780x81, 0x02, // Input (Data,Var,Abs) 91790xc0, // End Collection 93800xc0, // End Collection 94810x05, 0x0d, // Usage Page (Digitizers) 95820x09, 0x04, // Usage (Touch Screen) 97830xa1, 0x01, // Collection (Application) 99840x85, 0x04, // Report ID (4) 101850x09, 0x22, // Usage (Finger) 103860xa1, 0x02, // Collection (Logical) 105870x05, 0x0d, // Usage Page (Digitizers) 107880x95, 0x01, // Report Count (1) 109890x75, 0x06, // Report Size (6) 111900x09, 0x51, // Usage (Contact Id) 113910x15, 0x00, // Logical Minimum (0) 115920x25, 0x3f, // Logical Maximum (63) 117930x81, 0x02, // Input (Data,Var,Abs) 119940x09, 0x42, // Usage (Tip Switch) 121950x25, 0x01, // Logical Maximum (1) 123960x75, 0x01, // Report Size (1) 125970x95, 0x01, // Report Count (1) 127980x81, 0x02, // Input (Data,Var,Abs) 129990x75, 0x01, // Report Size (1) 1311000x95, 0x01, // Report Count (1) 1331010x81, 0x03, // Input (Cnst,Var,Abs) 1351020x05, 0x01, // Usage Page (Generic Desktop) 1371030x75, 0x10, // Report Size (16) 1391040x55, 0x0e, // Unit Exponent (-2) 1411050x65, 0x11, // Unit (SILinear: cm) 1431060x09, 0x30, // Usage (X) 1451070x26, 0xff, 0x7f, // Logical Maximum (32767) 1471080x35, 0x00, // Physical Minimum (0) 1501090x46, 0x15, 0x0c, // Physical Maximum (3093) 1521100x81, 0x42, // Input (Data,Var,Abs,Null) 1551110x09, 0x31, // Usage (Y) 1571120x26, 0xff, 0x7f, // Logical Maximum (32767) 1591130x46, 0xcb, 0x06, // Physical Maximum (1739) 1621140x81, 0x42, // Input (Data,Var,Abs,Null) 1651150x05, 0x0d, // Usage Page (Digitizers) 1671160x09, 0x30, // Usage (Tip Pressure) 1691170x26, 0xff, 0x1f, // Logical Maximum (8191) 1711180x75, 0x10, // Report Size (16) 1741190x95, 0x01, // Report Count (1) 1761200x81, 0x02, // Input (Data,Var,Abs) 1781210xc0, // End Collection 1801220x05, 0x0d, // Usage Page (Digitizers) 1811230x09, 0x22, // Usage (Finger) 1831240xa1, 0x02, // Collection (Logical) 1851250x05, 0x0d, // Usage Page (Digitizers) 1871260x95, 0x01, // Report Count (1) 1891270x75, 0x06, // Report Size (6) 1911280x09, 0x51, // Usage (Contact Id) 1931290x15, 0x00, // Logical Minimum (0) 1951300x25, 0x3f, // Logical Maximum (63) 1971310x81, 0x02, // Input (Data,Var,Abs) 1991320x09, 0x42, // Usage (Tip Switch) 2011330x25, 0x01, // Logical Maximum (1) 2031340x75, 0x01, // Report Size (1) 2051350x95, 0x01, // Report Count (1) 2071360x81, 0x02, // Input (Data,Var,Abs) 2091370x75, 0x01, // Report Size (1) 2111380x95, 0x01, // Report Count (1) 2131390x81, 0x03, // Input (Cnst,Var,Abs) 2151400x05, 0x01, // Usage Page (Generic Desktop) 2171410x75, 0x10, // Report Size (16) 2191420x55, 0x0e, // Unit Exponent (-2) 2211430x65, 0x11, // Unit (SILinear: cm) 2231440x09, 0x30, // Usage (X) 2251450x26, 0xff, 0x7f, // Logical Maximum (32767) 2271460x35, 0x00, // Physical Minimum (0) 2301470x46, 0x15, 0x0c, // Physical Maximum (3093) 2321480x81, 0x42, // Input (Data,Var,Abs,Null) 2351490x09, 0x31, // Usage (Y) 2371500x26, 0xff, 0x7f, // Logical Maximum (32767) 2391510x46, 0xcb, 0x06, // Physical Maximum (1739) 2421520x81, 0x42, // Input (Data,Var,Abs,Null) 2451530x05, 0x0d, // Usage Page (Digitizers) 2471540x09, 0x30, // Usage (Tip Pressure) 2491550x26, 0xff, 0x1f, // Logical Maximum (8191) 2511560x75, 0x10, // Report Size (16) 2541570x95, 0x01, // Report Count (1) 2561580x81, 0x02, // Input (Data,Var,Abs) 2581590xc0, // End Collection 2601600x05, 0x0d, // Usage Page (Digitizers) 2611610x09, 0x56, // Usage (Scan Time) 2631620x55, 0x00, // Unit Exponent (0) 2651630x65, 0x00, // Unit (None) 2671640x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 2691650x95, 0x01, // Report Count (1) 2741660x75, 0x20, // Report Size (32) 2761670x81, 0x02, // Input (Data,Var,Abs) 2781680x09, 0x54, // Usage (Contact Count) 2801690x25, 0x7f, // Logical Maximum (127) 2821700x95, 0x01, // Report Count (1) 2841710x75, 0x08, // Report Size (8) 2861720x81, 0x02, // Input (Data,Var,Abs) 2881730x75, 0x08, // Report Size (8) 2901740x95, 0x08, // Report Count (8) 2921750x81, 0x03, // Input (Cnst,Var,Abs) 2941760x85, 0x05, // Report ID (5) 2961770x09, 0x55, // Usage (Contact Max) 2981780x25, 0x0a, // Logical Maximum (10) 3001790x75, 0x08, // Report Size (8) 3021800x95, 0x01, // Report Count (1) 3041810xb1, 0x02, // Feature (Data,Var,Abs) 3061820x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 3081830x09, 0xc5, // Usage (Vendor Usage 0xc5) 3111840x85, 0x06, // Report ID (6) 3131850x15, 0x00, // Logical Minimum (0) 3151860x26, 0xff, 0x00, // Logical Maximum (255) 3171870x75, 0x08, // Report Size (8) 3201880x96, 0x00, 0x01, // Report Count (256) 3221890xb1, 0x02, // Feature (Data,Var,Abs) 3251900xc0, // End Collection 327191/* New in Firmware Version: HUION_M220_240524 */1920x05, 0x01, // Usage Page (Generic Desktop) 3281930x09, 0x01, // Usage (Pointer) 3301940xa1, 0x01, // Collection (Application) 3321950x09, 0x01, // Usage (Pointer) 3341960xa1, 0x00, // Collection (Physical) 3361970x05, 0x09, // Usage Page (Button) 3381980x19, 0x01, // UsageMinimum (1) 3401990x29, 0x03, // UsageMaximum (3) 3422000x15, 0x00, // Logical Minimum (0) 3442010x25, 0x01, // Logical Maximum (1) 3462020x85, 0x02, // Report ID (2) 3482030x95, 0x03, // Report Count (3) 3502040x75, 0x01, // Report Size (1) 3522050x81, 0x02, // Input (Data,Var,Abs) 3542060x95, 0x01, // Report Count (1) 3562070x75, 0x05, // Report Size (5) 3582080x81, 0x01, // Input (Cnst,Arr,Abs) 3602090x05, 0x01, // Usage Page (Generic Desktop) 3622100x09, 0x30, // Usage (X) 3642110x09, 0x31, // Usage (Y) 3662120x15, 0x81, // Logical Minimum (-127) 3682130x25, 0x7f, // Logical Maximum (127) 3702140x75, 0x08, // Report Size (8) 3722150x95, 0x02, // Report Count (2) 3742160x81, 0x06, // Input (Data,Var,Rel) 3762170x95, 0x04, // Report Count (4) 3782180x75, 0x08, // Report Size (8) 3802190x81, 0x01, // Input (Cnst,Arr,Abs) 3822200xc0, // End Collection 3842210xc0, // End Collection 3852220x05, 0x0d, // Usage Page (Digitizers) 3862230x09, 0x05, // Usage (Touch Pad) 3882240xa1, 0x01, // Collection (Application) 3902250x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 3922260x09, 0x0c, // Usage (Vendor Usage 0x0c) 3952270x15, 0x00, // Logical Minimum (0) 3972280x26, 0xff, 0x00, // Logical Maximum (255) 3992290x75, 0x08, // Report Size (8) 4022300x95, 0x10, // Report Count (16) 4042310x85, 0x3f, // Report ID (63) 4062320x81, 0x22, // Input (Data,Var,Abs,NoPref) 4082330xc0, // End Collection 4102340x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 4112350x09, 0x0c, // Usage (Vendor Usage 0x0c) 4142360xa1, 0x01, // Collection (Application) 4162370x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 4182380x09, 0x0c, // Usage (Vendor Usage 0x0c) 4212390x15, 0x00, // Logical Minimum (0) 4232400x26, 0xff, 0x00, // Logical Maximum (255) 4252410x85, 0x44, // Report ID (68) 4282420x75, 0x08, // Report Size (8) 4302430x96, 0x6b, 0x05, // Report Count (1387) 4322440x81, 0x00, // Input (Data,Arr,Abs) 4352450xc0, // End Collection 437246};247248#define PRE_240524_RDESC_SIZE 328249#define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */250#define FW_240524_RDESC_SIZE 438251#define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc)252253SEC(HID_BPF_RDESC_FIXUP)254int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx)255{256__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);257258if (!data)259return 0; /* EPERM check */260261if (hctx->size == FW_240524_RDESC_SIZE) {262__builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE);263return sizeof(fixed_rdesc);264}265266__builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE);267268return PRE_240524_RDESC_FIXED_SIZE;269}270271/*272* This tablet reports the 3rd button through invert, but this conflict273* with the normal eraser mode.274* Fortunately, before entering eraser mode, (so Invert = 1),275* the tablet always sends an out-of-proximity event.276* So we can detect that single event and:277* - if there was none but the invert bit was toggled: this is the278* third button279* - if there was this out-of-proximity event, we are entering280* eraser mode, and we will until the next out-of-proximity.281*/282SEC(HID_BPF_DEVICE_EVENT)283int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx)284{285__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);286287if (!data)288return 0; /* EPERM check */289290if (data[0] != 0x0a) /* not the pen report ID */291return 0;292293/* stylus is out of range */294if (!(data[1] & 0x40)) {295prev_was_out_of_range = true;296in_eraser_mode = false;297return 0;298}299300/* going into eraser mode (Invert = 1) only happens after an301* out of range event302*/303if (prev_was_out_of_range && (data[1] & 0x18))304in_eraser_mode = true;305306/* eraser mode works fine */307if (in_eraser_mode)308return 0;309310/* copy the Invert bit reported for the 3rd button in bit 7 */311if (data[1] & 0x08)312data[1] |= 0x20;313314/* clear Invert bit now that it was copied */315data[1] &= 0xf7;316317prev_was_out_of_range = false;318319return 0;320}321322HID_BPF_OPS(huion_Kamvas_pro_19) = {323.hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas_pro_19,324.hid_device_event = (void *)kamvas_pro_19_fix_3rd_button,325};326327SEC("syscall")328int probe(struct hid_bpf_probe_args *ctx)329{330331ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) ||332(ctx->rdesc_size == FW_240524_RDESC_SIZE));333if (ctx->retval)334ctx->retval = -EINVAL;335336/* ensure the kernel isn't fixed already */337if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */338ctx->retval = -EINVAL;339340struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid);341342if (!hctx) {343return ctx->retval = -EINVAL;344return 0;345}346347const char *name = hctx->hid->name;348349/* strip out TEST_PREFIX */350if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1))351name += sizeof(TEST_PREFIX) - 1;352353if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)))354ctx->retval = -EINVAL;355356hid_bpf_release_context(hctx);357358return 0;359}360361char _license[] SEC("license") = "GPL";362363364