Path: blob/master/drivers/hid/bpf/progs/XPPen__Deco02.bpf.c
38241 views
// SPDX-License-Identifier: GPL-2.0-only12#include "vmlinux.h"3#include "hid_bpf.h"4#include "hid_bpf_helpers.h"5#include "hid_report_helpers.h"6#include <bpf/bpf_tracing.h>78#define VID_UGEE 0x28BD9#define PID_DECO_02 0x08031011HID_BPF_CONFIG(12HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_02),13);1415/*16* Devices are:17* - Pad input, including pen (This is the only one we are interested in)18* - Pen input as mouse19* - Vendor20*21* Descriptors on main device are:22* - 7: Pen23* - 6: Vendor settings? Unclear24* - 3: Keyboard (This is what we want to modify)25* - 5: Feature report26*27* This creates three event nodes:28* - XP-PEN DECO 02 Stylus29* - XP-PEN DECO 0230* - XP-PEN DECO 02 Keyboard (Again, what we want to modify)31*32* # Report descriptor length: 188 bytes33* # 0x05, 0x0d, // Usage Page (Digitizers) 034* # 0x09, 0x02, // Usage (Pen) 235* # 0xa1, 0x01, // Collection (Application) 436* # 0x85, 0x07, // Report ID (7) 637* # 0x09, 0x20, // Usage (Stylus) 838* # 0xa1, 0x00, // Collection (Physical) 1039* # 0x09, 0x42, // Usage (Tip Switch) 1240* # 0x09, 0x44, // Usage (Barrel Switch) 1441* # 0x09, 0x45, // Usage (Eraser) 1642* # 0x09, 0x3c, // Usage (Invert) 1843* # 0x09, 0x32, // Usage (In Range) 2044* # 0x15, 0x00, // Logical Minimum (0) 2245* # 0x25, 0x01, // Logical Maximum (1) 2446* # 0x75, 0x01, // Report Size (1) 2647* # 0x95, 0x05, // Report Count (5) 2848* # 0x81, 0x02, // Input (Data,Var,Abs) 3049* # 0x95, 0x03, // Report Count (3) 3250* # 0x81, 0x03, // Input (Cnst,Var,Abs) 3451* # 0x05, 0x01, // Usage Page (Generic Desktop) 3652* # 0x09, 0x30, // Usage (X) 3853* # 0x15, 0x00, // Logical Minimum (0) 4054* # 0x26, 0x50, 0x57, // Logical Maximum (22352) 4255* # 0x55, 0x0d, // Unit Exponent (-3) 4556* # 0x65, 0x13, // Unit (EnglishLinear: in) 4757* # 0x35, 0x00, // Physical Minimum (0) 4958* # 0x46, 0x50, 0x57, // Physical Maximum (22352) 5159* # 0x75, 0x10, // Report Size (16) 5460* # 0x95, 0x01, // Report Count (1) 5661* # 0x81, 0x02, // Input (Data,Var,Abs) 5862* # 0x09, 0x31, // Usage (Y) 6063* # 0x15, 0x00, // Logical Minimum (0) 6264* # 0x26, 0x92, 0x36, // Logical Maximum (13970) 6465* # 0x55, 0x0d, // Unit Exponent (-3) 6766* # 0x65, 0x13, // Unit (EnglishLinear: in) 6967* # 0x35, 0x00, // Physical Minimum (0) 7168* # 0x46, 0x92, 0x36, // Physical Maximum (13970) 7369* # 0x75, 0x10, // Report Size (16) 7670* # 0x95, 0x01, // Report Count (1) 7871* # 0x81, 0x02, // Input (Data,Var,Abs) 8072* # 0x05, 0x0d, // Usage Page (Digitizers) 8273* # 0x09, 0x30, // Usage (Tip Pressure) 8474* # 0x15, 0x00, // Logical Minimum (0) 8675* # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 8876* # 0x75, 0x10, // Report Size (16) 9177* # 0x95, 0x01, // Report Count (1) 9378* # 0x81, 0x02, // Input (Data,Var,Abs) 9579* # 0xc0, // End Collection 9780* # 0xc0, // End Collection 9881* # 0x09, 0x0e, // Usage (Device Configuration) 9982* # 0xa1, 0x01, // Collection (Application) 10183* # 0x85, 0x05, // Report ID (5) 10384* # 0x09, 0x23, // Usage (Device Settings) 10585* # 0xa1, 0x02, // Collection (Logical) 10786* # 0x09, 0x52, // Usage (Inputmode) 10987* # 0x09, 0x53, // Usage (Device Index) 11188* # 0x25, 0x0a, // Logical Maximum (10) 11389* # 0x75, 0x08, // Report Size (8) 11590* # 0x95, 0x02, // Report Count (2) 11791* # 0xb1, 0x02, // Feature (Data,Var,Abs) 11992* # 0xc0, // End Collection 12193* # 0xc0, // End Collection 12294* # 0x05, 0x0c, // Usage Page (Consumer Devices) 12395* # 0x09, 0x36, // Usage (Function Buttons) 12596* # 0xa1, 0x00, // Collection (Physical) 12797* # 0x85, 0x06, // Report ID (6) 12998* # 0x05, 0x09, // Usage Page (Button) 13199* # 0x19, 0x01, // Usage Minimum (1) 133100* # 0x29, 0x20, // Usage Maximum (32) 135101* # 0x15, 0x00, // Logical Minimum (0) 137102* # 0x25, 0x01, // Logical Maximum (1) 139103* # 0x95, 0x20, // Report Count (32) 141104* # 0x75, 0x01, // Report Size (1) 143105* # 0x81, 0x02, // Input (Data,Var,Abs) 145106* # 0xc0, // End Collection 147107* # 0x05, 0x01, // Usage Page (Generic Desktop) 148108* # 0x09, 0x06, // Usage (Keyboard) 150109* # 0xa1, 0x01, // Collection (Application) 152110* # 0x85, 0x03, // Report ID (3) 154111* # 0x05, 0x07, // Usage Page (Keyboard) 156112* # 0x19, 0xe0, // Usage Minimum (224) 158113* # 0x29, 0xe7, // Usage Maximum (231) 160114* # 0x15, 0x00, // Logical Minimum (0) 162115* # 0x25, 0x01, // Logical Maximum (1) 164116* # 0x75, 0x01, // Report Size (1) 166117* # 0x95, 0x08, // Report Count (8) 168118* # 0x81, 0x02, // Input (Data,Var,Abs) 170119* # 0x05, 0x07, // Usage Page (Keyboard) 172120* # 0x19, 0x00, // Usage Minimum (0) 174121* # 0x29, 0xff, // Usage Maximum (255) 176122* # 0x26, 0xff, 0x00, // Logical Maximum (255) 178123* # 0x75, 0x08, // Report Size (8) 181124* # 0x95, 0x06, // Report Count (6) 183125* # 0x81, 0x00, // Input (Data,Arr,Abs) 185126* # 0xc0, // End Collection 187127*128* Key events; top to bottom:129* Buttons released: 03 00 00 00 00 00 00 00130* Button1: 03 00 05 00 00 00 00 00 -> 'b and B'131* Button2: 03 00 2c 00 00 00 00 00 -> 'Spacebar'132* Button3: 03 00 08 00 00 00 00 00 -> 'e and E'133* Button4: 03 00 0c 00 00 00 00 00 -> 'i and I'134* Button5: 03 05 1d 00 00 00 00 00 -> LeftControl + LeftAlt + 'z and Z'135* Button6: 03 01 16 00 00 00 00 00 -> LeftControl + 's and S'136*137* Dial Events:138* Clockwise: 03 01 2e 00 00 00 00 00 -> LeftControl + '= and +'139* Anticlockwise: 03 01 2d 00 00 00 00 00 -> LeftControl + '- and (underscore)'140*141* NOTE: Input event descriptions begin at byte 2, and progressively build142* towards byte 7 as each new key is pressed maintaining the press order.143* For example:144* BTN1 followed by BTN2 is 03 00 05 2c 00 00 00 00145* BTN2 followed by BTN1 is 03 00 2c 05 00 00 00 00146*147* Releasing a button causes its byte to be freed, and the next item in the list148* is pushed forwards. Dial events are released immediately after an event is149* registered (i.e. after each "click"), so will continually appear pushed150* backwards in the report.151*152* When a button with a modifier key is pressed, the button identifier stacks in153* an abnormal way, where the highest modifier byte always supersedes others.154* In these cases, the button with the higher modifier is always last.155* For example:156* BTN6 followed by BTN5 is 03 05 1d 16 00 00 00 00157* BTN5 followed by BTN6 is 03 05 1d 16 00 00 00 00158* BTN5 followed by BTN1 is 03 05 05 1d 00 00 00 00159*160* For three button presses in order, demonstrating strictly above rules:161* BTN6, BTN1, BTN5 is 03 05 05 1d 16 00 00 00162* BTN5, BTN1, BTN6 is 03 05 05 1d 16 00 00 00163*164* In short, when BTN5/6 are pressed, the order of operations is lost, as they165* will always float to the end when pressed in combination with others.166*167* Fortunately, all states are recorded in the same way, with no overlaps.168* Byte 1 can be used as a spare for the wheel, since this is for mod keys.169*/170171#define RDESC_SIZE_PAD 188172#define REPORT_SIZE_PAD 8173#define REPORT_ID_BUTTONS 3174#define PAD_BUTTON_COUNT 6175#define RDESC_KEYBOARD_OFFSET 148176177static const __u8 fixed_rdesc_pad[] = {178/* Copy of pen descriptor to avoid losing functionality */179UsagePage_Digitizers180Usage_Dig_Pen181CollectionApplication(182ReportId(7)183Usage_Dig_Stylus184CollectionPhysical(185Usage_Dig_TipSwitch186Usage_Dig_BarrelSwitch187Usage_Dig_Eraser188Usage_Dig_Invert189Usage_Dig_InRange190LogicalMinimum_i8(0)191LogicalMaximum_i8(1)192ReportSize(1)193ReportCount(5)194Input(Var|Abs)195ReportCount(3)196Input(Const) /* Input (Const, Var, Abs) */197UsagePage_GenericDesktop198Usage_GD_X199LogicalMinimum_i16(0)200LogicalMaximum_i16(22352)201UnitExponent(-3)202Unit(in) /* (EnglishLinear: in) */203PhysicalMinimum_i16(0)204PhysicalMaximum_i16(22352)205ReportSize(16)206ReportCount(1)207Input(Var|Abs)208Usage_GD_Y209LogicalMinimum_i16(0)210LogicalMaximum_i16(13970)211UnitExponent(-3)212Unit(in) /* (EnglishLinear: in) */213PhysicalMinimum_i16(0)214PhysicalMaximum_i16(13970)215ReportSize(16)216ReportCount(1)217Input(Var|Abs)218UsagePage_Digitizers219Usage_Dig_TipPressure220LogicalMinimum_i16(0)221LogicalMaximum_i16(8191)222ReportSize(16)223ReportCount(1)224Input(Var|Abs)225)226)227228/* FIXES BEGIN */229UsagePage_GenericDesktop230Usage_GD_Keypad231CollectionApplication(232ReportId(REPORT_ID_BUTTONS) /* Retain original ID on byte 0 */233ReportCount(1)234ReportSize(REPORT_SIZE_PAD)235UsagePage_Digitizers236Usage_Dig_TabletFunctionKeys237CollectionPhysical(238/* Byte 1: Dial state */239UsagePage_GenericDesktop240Usage_GD_Dial241LogicalMinimum_i8(-1)242LogicalMaximum_i8(1)243ReportCount(1)244ReportSize(REPORT_SIZE_PAD)245Input(Var|Rel)246/* Byte 2: Button state */247UsagePage_Button248ReportSize(1)249ReportCount(PAD_BUTTON_COUNT)250UsageMinimum_i8(0x01)251UsageMaximum_i8(PAD_BUTTON_COUNT) /* Number of buttons */252LogicalMinimum_i8(0x0)253LogicalMaximum_i8(0x1)254Input(Var|Abs)255/* Byte 3: Exists to be tablet pad */256UsagePage_Digitizers257Usage_Dig_BarrelSwitch258ReportCount(1)259ReportSize(1)260Input(Var|Abs)261ReportCount(7) /* Padding, to fill full report space */262Input(Const)263/* Byte 4/5: Exists to be a tablet pad */264UsagePage_GenericDesktop265Usage_GD_X266Usage_GD_Y267ReportCount(2)268ReportSize(8)269Input(Var|Abs)270/* Bytes 6/7: Padding, to match original length */271ReportCount(2)272ReportSize(8)273Input(Const)274)275FixedSizeVendorReport(RDESC_SIZE_PAD)276)277};278279SEC(HID_BPF_RDESC_FIXUP)280int BPF_PROG(xppen_deco02_rdesc_fixup, struct hid_bpf_ctx *hctx)281{282__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);283284if (!data)285return 0; /* EPERM Check */286287if (hctx->size == RDESC_SIZE_PAD) {288__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));289return sizeof(fixed_rdesc_pad);290}291292return 0;293}294295SEC(HID_BPF_DEVICE_EVENT)296int BPF_PROG(xppen_deco02_device_event, struct hid_bpf_ctx *hctx)297{298__u8 *data = hid_bpf_get_data(hctx, 0, REPORT_SIZE_PAD);299300if (!data || data[0] != REPORT_ID_BUTTONS)301return 0; /* EPERM or wrong report */302303__u8 dial_code = 0;304__u8 button_mask = 0;305size_t d;306307/* Start from 2; 0 is report ID, 1 is modifier keys, replaced by dial */308for (d = 2; d < 8; d++) {309switch (data[d]) {310case 0x2e:311dial_code = 1;312break;313case 0x2d:314dial_code = -1;315break;316/* below are buttons, top to bottom */317case 0x05:318button_mask |= BIT(0);319break;320case 0x2c:321button_mask |= BIT(1);322break;323case 0x08:324button_mask |= BIT(2);325break;326case 0x0c:327button_mask |= BIT(3);328break;329case 0x1d:330button_mask |= BIT(4);331break;332case 0x16:333button_mask |= BIT(05);334break;335default:336break;337}338}339340__u8 report[8] = { REPORT_ID_BUTTONS, dial_code, button_mask, 0x00 };341342__builtin_memcpy(data, report, sizeof(report));343return 0;344}345346HID_BPF_OPS(xppen_deco02) = {347.hid_rdesc_fixup = (void *)xppen_deco02_rdesc_fixup,348.hid_device_event = (void *)xppen_deco02_device_event,349};350351SEC("syscall")352int probe(struct hid_bpf_probe_args *ctx)353{354ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD ? -EINVAL : 0;355return 0;356}357358char _license[] SEC("license") = "GPL";359360361