Path: blob/master/drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c
26285 views
// SPDX-License-Identifier: GPL-2.0-only1/* Copyright (c) 2024 José Expósito2*/34#include "vmlinux.h"5#include "hid_bpf.h"6#include "hid_bpf_helpers.h"7#include <bpf/bpf_tracing.h>89#define VID_UGEE 0x28BD10#define PID_DECO_MINI_4 0x092911#define RDESC_SIZE_PAD 17712#define RDESC_SIZE_PEN 10913#define PAD_REPORT_ID 0x061415/*16* XP-Pen devices return a descriptor with the values the driver should use when17* one of its interfaces is queried. For this device the descriptor is:18*19* 0E 03 60 4F 88 3B 06 00 FF 1F D8 1320* ----- ----- ----- -----21* | | | |22* | | | `- Resolution: 5080 (13d8)23* | | `- Maximum pressure: 8191 (1FFF)24* | `- Logical maximum Y: 15240 (3B88)25* `- Logical maximum X: 20320 (4F60)26*27* The physical maximum is calculated as (logical_max * 1000) / resolution.28*/29#define LOGICAL_MAX_X 0x60, 0x4F30#define LOGICAL_MAX_Y 0x88, 0x3B31#define PHYSICAL_MAX_X 0xA0, 0x0F32#define PHYSICAL_MAX_Y 0xB8, 0x0B33#define PRESSURE_MAX 0xFF, 0x1F3435HID_BPF_CONFIG(36HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_MINI_4)37);3839/*40* The tablet send these values when the pad buttons are pressed individually:41*42* Buttons released: 06 00 00 00 00 00 00 0043* Button 1: 06 00 05 00 00 00 00 00 -> b44* Button 2: 06 00 08 00 00 00 00 00 -> e45* Button 3: 06 04 00 00 00 00 00 00 -> LAlt46* Button 4: 06 00 2c 00 00 00 00 00 -> Space47* Button 5: 06 01 16 00 00 00 00 00 -> LControl + s48* Button 6: 06 01 1d 00 00 00 00 00 -> LControl + z49*50* When multiple buttons are pressed at the same time, the values used to51* identify the buttons are identical, but they appear in different bytes of the52* record. For example, when button 2 (0x08) and button 1 (0x05) are pressed,53* this is the report:54*55* Buttons 2 and 1: 06 00 08 05 00 00 00 00 -> e + b56*57* Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the58* report.59*60* Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 361* and 5 generates this report:62*63* Buttons 3 and 5: 06 05 16 00 00 00 00 00 -> LControl + LAlt + s64* -- --65* | |66* | `- Button 5 (0x16)67* `- 0x05 = 0101. Button 3 is pressed68* ^69*70* pad_buttons contains a list of buttons that can be matched in71* HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit.72*/73static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2C, 0x16, 0x1D };7475static const __u8 fixed_pad_rdesc[] = {760x05, 0x01, /* Usage Page (Desktop), */770x09, 0x07, /* Usage (Keypad), */780xA1, 0x01, /* Collection (Application), */790x85, 0x06, /* Report ID (6), */800x05, 0x0D, /* Usage Page (Digitizer), */810x09, 0x39, /* Usage (Tablet Function Keys), */820xA0, /* Collection (Physical), */830x05, 0x09, /* Usage Page (Button), */840x75, 0x01, /* Report Size (1), */850x95, 0x06, /* Report Count (6), */860x19, 0x01, /* Usage Minimum (01h), */870x29, 0x06, /* Usage Maximum (06h), */880x14, /* Logical Minimum (0), */890x25, 0x01, /* Logical Maximum (1), */900x81, 0x02, /* Input (Variable), */910x95, 0x32, /* Report Count (50), */920x81, 0x01, /* Input (Constant), */930xC0, /* End Collection, */940xC0 /* End Collection */95};9697static const __u8 fixed_pen_rdesc[] = {980x05, 0x0d, /* Usage Page (Digitizers), */990x09, 0x01, /* Usage (Digitizer), */1000xa1, 0x01, /* Collection (Application), */1010x85, 0x07, /* Report ID (7), */1020x09, 0x20, /* Usage (Stylus), */1030xa1, 0x00, /* Collection (Physical), */1040x09, 0x42, /* Usage (Tip Switch), */1050x09, 0x44, /* Usage (Barrel Switch), */1060x09, 0x46, /* Usage (Tablet Pick), */1070x75, 0x01, /* Report Size (1), */1080x95, 0x03, /* Report Count (3), */1090x14, /* Logical Minimum (0), */1100x25, 0x01, /* Logical Maximum (1), */1110x81, 0x02, /* Input (Variable), */1120x95, 0x02, /* Report Count (2), */1130x81, 0x03, /* Input (Constant, Variable), */1140x09, 0x32, /* Usage (In Range), */1150x95, 0x01, /* Report Count (1), */1160x81, 0x02, /* Input (Variable), */1170x95, 0x02, /* Report Count (2), */1180x81, 0x03, /* Input (Constant, Variable), */1190x75, 0x10, /* Report Size (16), */1200x95, 0x01, /* Report Count (1), */1210x35, 0x00, /* Physical Minimum (0), */1220xa4, /* Push, */1230x05, 0x01, /* Usage Page (Desktop), */1240x09, 0x30, /* Usage (X), */1250x65, 0x13, /* Unit (Inch), */1260x55, 0x0d, /* Unit Exponent (-3), */1270x26, LOGICAL_MAX_X, /* Logical Maximum, */1280x46, PHYSICAL_MAX_X, /* Physical Maximum, */1290x81, 0x02, /* Input (Variable), */1300x09, 0x31, /* Usage (Y), */1310x26, LOGICAL_MAX_Y, /* Logical Maximum, */1320x46, PHYSICAL_MAX_Y, /* Physical Maximum, */1330x81, 0x02, /* Input (Variable), */1340xb4, /* Pop, */1350x09, 0x30, /* Usage (Tip Pressure), */1360x45, 0x00, /* Physical Maximum (0), */1370x26, PRESSURE_MAX, /* Logical Maximum, */1380x75, 0x0D, /* Report Size (13), */1390x95, 0x01, /* Report Count (1), */1400x81, 0x02, /* Input (Variable), */1410x75, 0x01, /* Report Size (1), */1420x95, 0x13, /* Report Count (19), */1430x81, 0x01, /* Input (Constant), */1440xc0, /* End Collection, */1450xc0, /* End Collection */146};147148static const size_t fixed_pad_rdesc_size = sizeof(fixed_pad_rdesc);149static const size_t fixed_pen_rdesc_size = sizeof(fixed_pen_rdesc);150151SEC(HID_BPF_RDESC_FIXUP)152int BPF_PROG(hid_rdesc_fixup_xppen_deco_mini_4, struct hid_bpf_ctx *hctx)153{154__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);155156if (!data)157return 0; /* EPERM check */158159if (hctx->size == RDESC_SIZE_PAD) {160__builtin_memcpy(data, fixed_pad_rdesc, fixed_pad_rdesc_size);161return fixed_pad_rdesc_size;162} else if (hctx->size == RDESC_SIZE_PEN) {163__builtin_memcpy(data, fixed_pen_rdesc, fixed_pen_rdesc_size);164return fixed_pen_rdesc_size;165}166167return 0;168}169170SEC(HID_BPF_DEVICE_EVENT)171int BPF_PROG(hid_device_event_xppen_deco_mini_4, struct hid_bpf_ctx *hctx)172{173__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 8 /* size */);174__u8 button_mask = 0;175int d, b;176177if (!data)178return 0; /* EPERM check */179180if (data[0] != PAD_REPORT_ID)181return 0;182183/* data[1] stores the status of BTN_2 in the 3rd bit*/184if (data[1] & BIT(2))185button_mask |= BIT(2);186187/* The rest of the descriptor stores the buttons as in pad_buttons */188for (d = 2; d < 8; d++) {189for (b = 0; b < sizeof(pad_buttons); b++) {190if (data[d] != 0 && data[d] == pad_buttons[b])191button_mask |= BIT(b);192}193}194195__u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00};196197__builtin_memcpy(data, report, sizeof(report));198199return 0;200}201202HID_BPF_OPS(deco_mini_4) = {203.hid_device_event = (void *)hid_device_event_xppen_deco_mini_4,204.hid_rdesc_fixup = (void *)hid_rdesc_fixup_xppen_deco_mini_4,205};206207SEC("syscall")208int probe(struct hid_bpf_probe_args *ctx)209{210/*211* The device has 2 modes: The compatibility mode, enabled by default,212* and the raw mode, that can be activated by sending a buffer of magic213* data to a certain USB endpoint.214*215* Depending on the mode, different interfaces of the device are used:216* - First interface: Pad in compatibility mode217* - Second interface: Pen in compatibility mode218* - Third interface: Only used in raw mode219*220* We'll use the device in compatibility mode.221*/222ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD &&223ctx->rdesc_size != RDESC_SIZE_PEN;224if (ctx->retval)225ctx->retval = -EINVAL;226227return 0;228}229230char _license[] SEC("license") = "GPL";231232233