Path: blob/master/drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c
38242 views
// SPDX-License-Identifier: GPL-2.0-only1/* Copyright (c) 2025 Red Hat2*/34#include "vmlinux.h"5#include "hid_bpf.h"6#include "hid_bpf_helpers.h"7#include "hid_report_helpers.h"8#include <bpf/bpf_tracing.h>910#define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */11#define PID_DECO_01_V3 0x09471213HID_BPF_CONFIG(14HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_01_V3),15);1617/*18* Default report descriptor reports:19* - a report descriptor for the pad buttons, reported as key sequences20* - a report descriptor for the pen21* - a vendor-specific report descriptor22*23* The Pad report descriptor, see24* https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/issues/5425*26* # Report descriptor length: 102 bytes27* 0x05, 0x01, // Usage Page (Generic Desktop) 028* 0x09, 0x02, // Usage (Mouse) 229* 0xa1, 0x01, // Collection (Application) 430* 0x85, 0x09, // Report ID (9) 631* 0x09, 0x01, // Usage (Pointer) 832* 0xa1, 0x00, // Collection (Physical) 1033* 0x05, 0x09, // Usage Page (Button) 1234* 0x19, 0x01, // UsageMinimum (1) 1435* 0x29, 0x03, // UsageMaximum (3) 1636* 0x15, 0x00, // Logical Minimum (0) 1837* 0x25, 0x01, // Logical Maximum (1) 2038* 0x95, 0x03, // Report Count (3) 2239* 0x75, 0x01, // Report Size (1) 2440* 0x81, 0x02, // Input (Data,Var,Abs) 2641* 0x95, 0x05, // Report Count (5) 2842* 0x81, 0x01, // Input (Cnst,Arr,Abs) 3043* 0x05, 0x01, // Usage Page (Generic Desktop) 3244* 0x09, 0x30, // Usage (X) 3445* 0x09, 0x31, // Usage (Y) 3646* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 3847* 0x95, 0x02, // Report Count (2) 4148* 0x75, 0x10, // Report Size (16) 4349* 0x81, 0x02, // Input (Data,Var,Abs) 4550* 0x05, 0x0d, // Usage Page (Digitizers) 4751* 0x09, 0x30, // Usage (Tip Pressure) 4952* 0x26, 0xff, 0x07, // Logical Maximum (2047) 5153* 0x95, 0x01, // Report Count (1) 5454* 0x75, 0x10, // Report Size (16) 5655* 0x81, 0x02, // Input (Data,Var,Abs) 5856* 0xc0, // End Collection 6057* 0xc0, // End Collection 6158* 0x05, 0x01, // Usage Page (Generic Desktop) 6259* 0x09, 0x06, // Usage (Keyboard) 6460* 0xa1, 0x01, // Collection (Application) 6661* 0x85, 0x06, // Report ID (6) 6862* 0x05, 0x07, // Usage Page (Keyboard/Keypad) 7063* 0x19, 0xe0, // UsageMinimum (224) 7264* 0x29, 0xe7, // UsageMaximum (231) 7465* 0x15, 0x00, // Logical Minimum (0) 7666* 0x25, 0x01, // Logical Maximum (1) 7867* 0x75, 0x01, // Report Size (1) 8068* 0x95, 0x08, // Report Count (8) 8269* 0x81, 0x02, // Input (Data,Var,Abs) 8470* 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8671* 0x19, 0x00, // UsageMinimum (0) 8872* 0x29, 0xff, // UsageMaximum (255) 9073* 0x26, 0xff, 0x00, // Logical Maximum (255) 9274* 0x75, 0x08, // Report Size (8) 9575* 0x95, 0x06, // Report Count (6) 9776* 0x81, 0x00, // Input (Data,Arr,Abs) 9977* 0xc0, // End Collection 10178*79* And key events for buttons top->bottom are:80* Buttons released: 06 00 00 00 00 00 00 0081* Button1: 06 00 05 00 00 00 00 00 -> b82* Button2: 06 00 08 00 00 00 00 00 -> e83* Button3: 06 04 00 00 00 00 00 00 -> LAlt84* Button4: 06 00 2c 00 00 00 00 00 -> Space85* Button5: 06 01 16 00 00 00 00 00 -> LControl + s86* Button6: 06 01 1d 00 00 00 00 00 -> LControl + z87* Button7: 06 01 57 00 00 00 00 00 -> LControl + Keypad Plus88* Button8: 06 01 56 00 00 00 00 00 -> LControl + Keypad Dash89*90* When multiple buttons are pressed at the same time, the values used to91* identify the buttons are identical, but they appear in different bytes of the92* record. For example, when button 2 (0x08) and button 1 (0x05) are pressed,93* this is the report:94*95* Buttons 2 and 1: 06 00 08 05 00 00 00 00 -> e + b96*97* Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the98* report.99*100* Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 3101* and 5 generates this report:102*103* Buttons 3 and 5: 06 05 16 00 00 00 00 00 -> LControl + LAlt + s104* -- --105* | |106* | `- Button 5 (0x16)107* `- 0x05 = 0101. Button 3 is pressed108* ^109*110* pad_buttons contains a list of buttons that can be matched in111* HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit.112*113*114* The Pen report descriptor announces a wrong tilt range:115*116* Report descriptor length: 109 bytes117* 0x05, 0x0d, // Usage Page (Digitizers) 0118* 0x09, 0x02, // Usage (Pen) 2119* 0xa1, 0x01, // Collection (Application) 4120* 0x85, 0x07, // Report ID (7) 6121* 0x09, 0x20, // Usage (Stylus) 8122* 0xa1, 0x01, // Collection (Application) 10123* 0x09, 0x42, // Usage (Tip Switch) 12124* 0x09, 0x44, // Usage (Barrel Switch) 14125* 0x09, 0x45, // Usage (Eraser) 16126* 0x09, 0x3c, // Usage (Invert) 18127* 0x15, 0x00, // Logical Minimum (0) 20128* 0x25, 0x01, // Logical Maximum (1) 22129* 0x75, 0x01, // Report Size (1) 24130* 0x95, 0x04, // Report Count (4) 26131* 0x81, 0x02, // Input (Data,Var,Abs) 28132* 0x95, 0x01, // Report Count (1) 30133* 0x81, 0x03, // Input (Cnst,Var,Abs) 32134* 0x09, 0x32, // Usage (In Range) 34135* 0x95, 0x01, // Report Count (1) 36136* 0x81, 0x02, // Input (Data,Var,Abs) 38137* 0x95, 0x02, // Report Count (2) 40138* 0x81, 0x03, // Input (Cnst,Var,Abs) 42139* 0x75, 0x10, // Report Size (16) 44140* 0x95, 0x01, // Report Count (1) 46141* 0x35, 0x00, // Physical Minimum (0) 48142* 0xa4, // Push 50143* 0x05, 0x01, // Usage Page (Generic Desktop) 51144* 0x09, 0x30, // Usage (X) 53145* 0x65, 0x13, // Unit (EnglishLinear: in) 55146* 0x55, 0x0d, // Unit Exponent (-3) 57147* 0x46, 0x10, 0x27, // Physical Maximum (10000) 59148* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 62149* 0x81, 0x02, // Input (Data,Var,Abs) 65150* 0x09, 0x31, // Usage (Y) 67151* 0x46, 0x6a, 0x18, // Physical Maximum (6250) 69152* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 72153* 0x81, 0x02, // Input (Data,Var,Abs) 75154* 0xb4, // Pop 77155* 0x09, 0x30, // Usage (X) 78156* 0x45, 0x00, // Physical Maximum (0) 80157* 0x26, 0xff, 0x3f, // Logical Maximum (16383) 82158* 0x81, 0x42, // Input (Data,Var,Abs,Null) 85159* 0x09, 0x3d, // Usage (Start) 87160* 0x15, 0x81, // Logical Minimum (-127) 89 <- Change from -127 to -60161* 0x25, 0x7f, // Logical Maximum (127) 91 <- Change from 127 to 60162* 0x75, 0x08, // Report Size (8) 93163* 0x95, 0x01, // Report Count (1) 95164* 0x81, 0x02, // Input (Data,Var,Abs) 97165* 0x09, 0x3e, // Usage (Select) 99166* 0x15, 0x81, // Logical Minimum (-127) 101 <- Change from -127 to -60167* 0x25, 0x7f, // Logical Maximum (127) 103 <- Change from 127 to 60168* 0x81, 0x02, // Input (Data,Var,Abs) 105169* 0xc0, // End Collection 107170* 0xc0, // End Collection 108171*/172173#define PEN_REPORT_DESCRIPTOR_LENGTH 109174#define PAD_REPORT_DESCRIPTOR_LENGTH 102175#define PAD_REPORT_LENGTH 8176#define PAD_REPORT_ID 6177#define PAD_NUM_BUTTONS 8178179static const __u8 fixed_rdesc_pad[] = {180UsagePage_GenericDesktop181Usage_GD_Keypad182CollectionApplication(183// Byte 0 in report is the report ID184ReportId(PAD_REPORT_ID)185ReportCount(1)186ReportSize(8)187UsagePage_Digitizers188Usage_Dig_TabletFunctionKeys189CollectionPhysical(190// Byte 1 is the button state191UsagePage_Button192UsageMinimum_i8(0x01)193UsageMaximum_i8(PAD_NUM_BUTTONS)194LogicalMinimum_i8(0x0)195LogicalMaximum_i8(0x1)196ReportCount(PAD_NUM_BUTTONS)197ReportSize(1)198Input(Var|Abs)199// Byte 2 in report - just exists so we get to be a tablet pad200UsagePage_Digitizers201Usage_Dig_BarrelSwitch // BTN_STYLUS202ReportCount(1)203ReportSize(1)204Input(Var|Abs)205ReportCount(7) // padding206Input(Const)207// Bytes 3/4 in report - just exists so we get to be a tablet pad208UsagePage_GenericDesktop209Usage_GD_X210Usage_GD_Y211ReportCount(2)212ReportSize(8)213Input(Var|Abs)214// Byte 5-7 are padding so we match the original report lengtth215ReportCount(3)216ReportSize(8)217Input(Const)218)219)220};221222SEC(HID_BPF_RDESC_FIXUP)223int BPF_PROG(xppen_deco01v3_rdesc_fixup, struct hid_bpf_ctx *hctx)224{225__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);226227const __u8 wrong_logical_range[] = {0x15, 0x81, 0x25, 0x7f};228const __u8 correct_logical_range[] = {0x15, 0xc4, 0x25, 0x3c};229230if (!data)231return 0; /* EPERM check */232233switch (hctx->size) {234case PAD_REPORT_DESCRIPTOR_LENGTH:235__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));236return sizeof(fixed_rdesc_pad);237case PEN_REPORT_DESCRIPTOR_LENGTH:238if (__builtin_memcmp(&data[89], wrong_logical_range,239sizeof(wrong_logical_range)) == 0)240__builtin_memcpy(&data[89], correct_logical_range,241sizeof(correct_logical_range));242if (__builtin_memcmp(&data[101], wrong_logical_range,243sizeof(wrong_logical_range)) == 0)244__builtin_memcpy(&data[101], correct_logical_range,245sizeof(correct_logical_range));246break;247}248249return 0;250}251252SEC(HID_BPF_DEVICE_EVENT)253int BPF_PROG(xppen_deco01v3_device_event, struct hid_bpf_ctx *hctx)254{255static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2c, 0x16, 0x1d, 0x57, 0x56 };256__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PAD_REPORT_LENGTH /* size */);257258if (!data)259return 0; /* EPERM check */260261if (data[0] == PAD_REPORT_ID) {262__u8 button_mask = 0;263size_t d, b;264265/* data[1] stores the status of BTN_2 in the 3rd bit*/266if (data[1] & BIT(2))267button_mask |= BIT(2);268269/* The rest of the descriptor stores the buttons as in pad_buttons */270for (d = 2; d < 8; d++) {271for (b = 0; b < sizeof(pad_buttons); b++) {272if (data[d] != 0 && data[d] == pad_buttons[b])273button_mask |= BIT(b);274}275}276277__u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00};278279__builtin_memcpy(data, report, sizeof(report));280}281return 0;282}283284HID_BPF_OPS(xppen_deco01v3) = {285.hid_rdesc_fixup = (void *)xppen_deco01v3_rdesc_fixup,286.hid_device_event = (void *)xppen_deco01v3_device_event,287};288289SEC("syscall")290int probe(struct hid_bpf_probe_args *ctx)291{292switch (ctx->rdesc_size) {293case PAD_REPORT_DESCRIPTOR_LENGTH:294case PEN_REPORT_DESCRIPTOR_LENGTH:295ctx->retval = 0;296break;297default:298ctx->retval = -EINVAL;299}300301return 0;302}303304char _license[] SEC("license") = "GPL";305306307