brintos

brintos / linux-shallow public Read only

0
0
Text · 9.5 KiB · 46d5c45 Raw
232 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2024 José Expósito3 */4 5#include "vmlinux.h"6#include "hid_bpf.h"7#include "hid_bpf_helpers.h"8#include <bpf/bpf_tracing.h>9 10#define VID_UGEE	0x28BD11#define PID_DECO_MINI_4	0x092912#define RDESC_SIZE_PAD	17713#define RDESC_SIZE_PEN	10914#define PAD_REPORT_ID	0x0615 16/*17 * XP-Pen devices return a descriptor with the values the driver should use when18 * one of its interfaces is queried. For this device the descriptor is:19 *20 * 0E 03 60 4F 88 3B 06 00 FF 1F D8 1321 *       ----- -----       ----- -----22 *         |     |           |     |23 *         |     |           |     `- Resolution: 5080 (13d8)24 *         |     |           `- Maximum pressure: 8191 (1FFF)25 *         |     `- Logical maximum Y: 15240 (3B88)26 *         `- Logical maximum X: 20320 (4F60)27 *28 * The physical maximum is calculated as (logical_max * 1000) / resolution.29 */30#define LOGICAL_MAX_X	0x60, 0x4F31#define LOGICAL_MAX_Y	0x88, 0x3B32#define PHYSICAL_MAX_X	0xA0, 0x0F33#define PHYSICAL_MAX_Y	0xB8, 0x0B34#define PRESSURE_MAX	0xFF, 0x1F35 36HID_BPF_CONFIG(37	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_MINI_4)38);39 40/*41 * The tablet send these values when the pad buttons are pressed individually:42 *43 *   Buttons released: 06 00 00 00 00 00 00 0044 *   Button 1:         06 00 05 00 00 00 00 00 -> b45 *   Button 2:         06 00 08 00 00 00 00 00 -> e46 *   Button 3:         06 04 00 00 00 00 00 00 -> LAlt47 *   Button 4:         06 00 2c 00 00 00 00 00 -> Space48 *   Button 5:         06 01 16 00 00 00 00 00 -> LControl + s49 *   Button 6:         06 01 1d 00 00 00 00 00 -> LControl + z50 *51 * When multiple buttons are pressed at the same time, the values used to52 * identify the buttons are identical, but they appear in different bytes of the53 * record. For example, when button 2 (0x08) and button 1 (0x05) are pressed,54 * this is the report:55 *56 *   Buttons 2 and 1:  06 00 08 05 00 00 00 00 -> e + b57 *58 * Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the59 * report.60 *61 * Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 362 * and 5 generates this report:63 *64 *   Buttons 3 and 5:  06 05 16 00 00 00 00 00 -> LControl + LAlt + s65 *                        -- --66 *                         |  |67 *                         |  `- Button 5 (0x16)68 *                         `- 0x05 = 0101. Button 3 is pressed69 *                                    ^70 *71 * pad_buttons contains a list of buttons that can be matched in72 * HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit.73 */74static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2C, 0x16, 0x1D };75 76static const __u8 fixed_pad_rdesc[] = {77	0x05, 0x01,           /*  Usage Page (Desktop),                   */78	0x09, 0x07,           /*  Usage (Keypad),                         */79	0xA1, 0x01,           /*  Collection (Application),               */80	0x85, 0x06,           /*      Report ID (6),                      */81	0x05, 0x0D,           /*      Usage Page (Digitizer),             */82	0x09, 0x39,           /*      Usage (Tablet Function Keys),       */83	0xA0,                 /*      Collection (Physical),              */84	0x05, 0x09,           /*          Usage Page (Button),            */85	0x75, 0x01,           /*          Report Size (1),                */86	0x95, 0x06,           /*          Report Count (6),               */87	0x19, 0x01,           /*          Usage Minimum (01h),            */88	0x29, 0x06,           /*          Usage Maximum (06h),            */89	0x14,                 /*          Logical Minimum (0),            */90	0x25, 0x01,           /*          Logical Maximum (1),            */91	0x81, 0x02,           /*          Input (Variable),               */92	0x95, 0x32,           /*          Report Count (50),              */93	0x81, 0x01,           /*          Input (Constant),               */94	0xC0,                 /*      End Collection,                     */95	0xC0                  /*  End Collection                          */96};97 98static const __u8 fixed_pen_rdesc[] = {99	0x05, 0x0d,           /*  Usage Page (Digitizers),                */100	0x09, 0x01,           /*  Usage (Digitizer),                      */101	0xa1, 0x01,           /*  Collection (Application),               */102	0x85, 0x07,           /*      Report ID (7),                      */103	0x09, 0x20,           /*      Usage (Stylus),                     */104	0xa1, 0x00,           /*      Collection (Physical),              */105	0x09, 0x42,           /*          Usage (Tip Switch),             */106	0x09, 0x44,           /*          Usage (Barrel Switch),          */107	0x09, 0x46,           /*          Usage (Tablet Pick),            */108	0x75, 0x01,           /*          Report Size (1),                */109	0x95, 0x03,           /*          Report Count (3),               */110	0x14,                 /*          Logical Minimum (0),            */111	0x25, 0x01,           /*          Logical Maximum (1),            */112	0x81, 0x02,           /*          Input (Variable),               */113	0x95, 0x02,           /*          Report Count (2),               */114	0x81, 0x03,           /*          Input (Constant, Variable),     */115	0x09, 0x32,           /*          Usage (In Range),               */116	0x95, 0x01,           /*          Report Count (1),               */117	0x81, 0x02,           /*          Input (Variable),               */118	0x95, 0x02,           /*          Report Count (2),               */119	0x81, 0x03,           /*          Input (Constant, Variable),     */120	0x75, 0x10,           /*          Report Size (16),               */121	0x95, 0x01,           /*          Report Count (1),               */122	0x35, 0x00,           /*          Physical Minimum (0),           */123	0xa4,                 /*          Push,                           */124	0x05, 0x01,           /*          Usage Page (Desktop),           */125	0x09, 0x30,           /*          Usage (X),                      */126	0x65, 0x13,           /*          Unit (Inch),                    */127	0x55, 0x0d,           /*          Unit Exponent (-3),             */128	0x26, LOGICAL_MAX_X,  /*          Logical Maximum,                */129	0x46, PHYSICAL_MAX_X, /*          Physical Maximum,               */130	0x81, 0x02,           /*          Input (Variable),               */131	0x09, 0x31,           /*          Usage (Y),                      */132	0x26, LOGICAL_MAX_Y,  /*          Logical Maximum,                */133	0x46, PHYSICAL_MAX_Y, /*          Physical Maximum,               */134	0x81, 0x02,           /*          Input (Variable),               */135	0xb4,                 /*          Pop,                            */136	0x09, 0x30,           /*          Usage (Tip Pressure),           */137	0x45, 0x00,           /*          Physical Maximum (0),           */138	0x26, PRESSURE_MAX,   /*          Logical Maximum,                */139	0x75, 0x0D,           /*          Report Size (13),               */140	0x95, 0x01,           /*          Report Count (1),               */141	0x81, 0x02,           /*          Input (Variable),               */142	0x75, 0x01,           /*          Report Size (1),                */143	0x95, 0x13,           /*          Report Count (19),              */144	0x81, 0x01,           /*          Input (Constant),               */145	0xc0,                 /*      End Collection,                     */146	0xc0,                 /*  End Collection                          */147};148 149static const size_t fixed_pad_rdesc_size = sizeof(fixed_pad_rdesc);150static const size_t fixed_pen_rdesc_size = sizeof(fixed_pen_rdesc);151 152SEC(HID_BPF_RDESC_FIXUP)153int BPF_PROG(hid_rdesc_fixup_xppen_deco_mini_4, struct hid_bpf_ctx *hctx)154{155	__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);156 157	if (!data)158		return 0; /* EPERM check */159 160	if (hctx->size == RDESC_SIZE_PAD) {161		__builtin_memcpy(data, fixed_pad_rdesc, fixed_pad_rdesc_size);162		return fixed_pad_rdesc_size;163	} else if (hctx->size == RDESC_SIZE_PEN) {164		__builtin_memcpy(data, fixed_pen_rdesc, fixed_pen_rdesc_size);165		return fixed_pen_rdesc_size;166	}167 168	return 0;169}170 171SEC(HID_BPF_DEVICE_EVENT)172int BPF_PROG(hid_device_event_xppen_deco_mini_4, struct hid_bpf_ctx *hctx)173{174	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 8 /* size */);175	__u8 button_mask = 0;176	int d, b;177 178	if (!data)179		return 0; /* EPERM check */180 181	if (data[0] != PAD_REPORT_ID)182		return 0;183 184	/* data[1] stores the status of BTN_2 in the 3rd bit*/185	if (data[1] & BIT(2))186		button_mask |= BIT(2);187 188	/* The rest of the descriptor stores the buttons as in pad_buttons */189	for (d = 2; d < 8; d++) {190		for (b = 0; b < sizeof(pad_buttons); b++) {191			if (data[d] != 0 && data[d] == pad_buttons[b])192				button_mask |= BIT(b);193		}194	}195 196	__u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00};197 198	__builtin_memcpy(data, report, sizeof(report));199 200	return 0;201}202 203HID_BPF_OPS(deco_mini_4) = {204	.hid_device_event = (void *)hid_device_event_xppen_deco_mini_4,205	.hid_rdesc_fixup = (void *)hid_rdesc_fixup_xppen_deco_mini_4,206};207 208SEC("syscall")209int probe(struct hid_bpf_probe_args *ctx)210{211	/*212	 * The device has 2 modes: The compatibility mode, enabled by default,213	 * and the raw mode, that can be activated by sending a buffer of magic214	 * data to a certain USB endpoint.215	 *216	 * Depending on the mode, different interfaces of the device are used:217	 * - First interface:  Pad in compatibility mode218	 * - Second interface: Pen in compatibility mode219	 * - Third interface:  Only used in raw mode220	 *221	 * We'll use the device in compatibility mode.222	 */223	ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD &&224		      ctx->rdesc_size != RDESC_SIZE_PEN;225	if (ctx->retval)226		ctx->retval = -EINVAL;227 228	return 0;229}230 231char _license[] SEC("license") = "GPL";232