xref: /linux/drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c (revision 637315cb400eed1dbe721954fea437a61a2d65b2)
1*857e71cbSNikhil Chatterjee // SPDX-License-Identifier: GPL-2.0-only
2*857e71cbSNikhil Chatterjee #include "vmlinux.h"
3*857e71cbSNikhil Chatterjee #include "hid_bpf.h"
4*857e71cbSNikhil Chatterjee #include "hid_bpf_helpers.h"
5*857e71cbSNikhil Chatterjee #include <bpf/bpf_tracing.h>
6*857e71cbSNikhil Chatterjee 
7*857e71cbSNikhil Chatterjee /*
8*857e71cbSNikhil Chatterjee  * Huion Inspiroy Frego M Pen Tablet
9*857e71cbSNikhil Chatterjee  * Model L610
10*857e71cbSNikhil Chatterjee  * 256c:8251 (Bluetooth)
11*857e71cbSNikhil Chatterjee  * 256c:2012 (USB)
12*857e71cbSNikhil Chatterjee  */
13*857e71cbSNikhil Chatterjee #define VID_HUION			0x256C
14*857e71cbSNikhil Chatterjee #define PID_INSPIROY_FREGO_M		0x8251
15*857e71cbSNikhil Chatterjee #define PID_L610			0x2012
16*857e71cbSNikhil Chatterjee 
17*857e71cbSNikhil Chatterjee #define PEN_RDESC_SIZE			125
18*857e71cbSNikhil Chatterjee #define SECONDARY_SWITCH_OFFSET		17
19*857e71cbSNikhil Chatterjee 
20*857e71cbSNikhil Chatterjee HID_BPF_CONFIG(
21*857e71cbSNikhil Chatterjee 	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_FREGO_M),
22*857e71cbSNikhil Chatterjee 	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_L610)
23*857e71cbSNikhil Chatterjee );
24*857e71cbSNikhil Chatterjee 
25*857e71cbSNikhil Chatterjee /*
26*857e71cbSNikhil Chatterjee  * The pen descriptor reports the second side button as Secondary Tip Switch
27*857e71cbSNikhil Chatterjee  * instead of Secondary Barrel Switch.
28*857e71cbSNikhil Chatterjee  *
29*857e71cbSNikhil Chatterjee  * Relevant part of the original pen report descriptor:
30*857e71cbSNikhil Chatterjee  *
31*857e71cbSNikhil Chatterjee  * 0x09, 0x42,       // Usage (Tip Switch)                  12
32*857e71cbSNikhil Chatterjee  * 0x09, 0x44,       // Usage (Barrel Switch)               14
33*857e71cbSNikhil Chatterjee  * 0x09, 0x43,       // Usage (Secondary Tip Switch)        16 <- change to 0x5a
34*857e71cbSNikhil Chatterjee  * 0x09, 0x3c,       // Usage (Invert)                      18
35*857e71cbSNikhil Chatterjee  * 0x09, 0x45,       // Usage (Eraser)                      20
36*857e71cbSNikhil Chatterjee  * 0x15, 0x00,       // Logical Minimum (0)                 22
37*857e71cbSNikhil Chatterjee  * 0x25, 0x01,       // Logical Maximum (1)                 24
38*857e71cbSNikhil Chatterjee  */
39*857e71cbSNikhil Chatterjee SEC(HID_BPF_RDESC_FIXUP)
40*857e71cbSNikhil Chatterjee int BPF_PROG(fix_secondary_barrel_rdesc, struct hid_bpf_ctx *hctx)
41*857e71cbSNikhil Chatterjee {
42*857e71cbSNikhil Chatterjee 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
43*857e71cbSNikhil Chatterjee 
44*857e71cbSNikhil Chatterjee 	if (!data)
45*857e71cbSNikhil Chatterjee 		return 0; /* EPERM check */
46*857e71cbSNikhil Chatterjee 
47*857e71cbSNikhil Chatterjee 	if (hctx->size != PEN_RDESC_SIZE)
48*857e71cbSNikhil Chatterjee 		return 0;
49*857e71cbSNikhil Chatterjee 
50*857e71cbSNikhil Chatterjee 	if (data[0] != 0x05 || data[1] != 0x0d || /* Usage Page (Digitizers) */
51*857e71cbSNikhil Chatterjee 	    data[2] != 0x09 || data[3] != 0x02 || /* Usage (Pen) */
52*857e71cbSNikhil Chatterjee 	    data[16] != 0x09 ||
53*857e71cbSNikhil Chatterjee 	    data[SECONDARY_SWITCH_OFFSET] != 0x43) /* Secondary Tip Switch */
54*857e71cbSNikhil Chatterjee 		return 0;
55*857e71cbSNikhil Chatterjee 
56*857e71cbSNikhil Chatterjee 	data[SECONDARY_SWITCH_OFFSET] = 0x5a;
57*857e71cbSNikhil Chatterjee 
58*857e71cbSNikhil Chatterjee 	return 0;
59*857e71cbSNikhil Chatterjee }
60*857e71cbSNikhil Chatterjee 
61*857e71cbSNikhil Chatterjee HID_BPF_OPS(fix_secondary_barrel) = {
62*857e71cbSNikhil Chatterjee 	.hid_rdesc_fixup = (void *)fix_secondary_barrel_rdesc,
63*857e71cbSNikhil Chatterjee };
64*857e71cbSNikhil Chatterjee 
65*857e71cbSNikhil Chatterjee SEC("syscall")
66*857e71cbSNikhil Chatterjee int probe(struct hid_bpf_probe_args *ctx)
67*857e71cbSNikhil Chatterjee {
68*857e71cbSNikhil Chatterjee 	ctx->retval = ctx->rdesc_size != PEN_RDESC_SIZE;
69*857e71cbSNikhil Chatterjee 	if (ctx->retval) {
70*857e71cbSNikhil Chatterjee 		ctx->retval = -EINVAL;
71*857e71cbSNikhil Chatterjee 		return 0;
72*857e71cbSNikhil Chatterjee 	}
73*857e71cbSNikhil Chatterjee 
74*857e71cbSNikhil Chatterjee 	if (ctx->rdesc[0] != 0x05 || ctx->rdesc[1] != 0x0d || /* Usage Page (Digitizers) */
75*857e71cbSNikhil Chatterjee 	    ctx->rdesc[2] != 0x09 || ctx->rdesc[3] != 0x02 || /* Usage (Pen) */
76*857e71cbSNikhil Chatterjee 	    ctx->rdesc[16] != 0x09 ||
77*857e71cbSNikhil Chatterjee 	    ctx->rdesc[SECONDARY_SWITCH_OFFSET] != 0x43) { /* Secondary Tip Switch */
78*857e71cbSNikhil Chatterjee 		ctx->retval = -EINVAL;
79*857e71cbSNikhil Chatterjee 		return 0;
80*857e71cbSNikhil Chatterjee 	}
81*857e71cbSNikhil Chatterjee 
82*857e71cbSNikhil Chatterjee 	ctx->retval = 0;
83*857e71cbSNikhil Chatterjee 
84*857e71cbSNikhil Chatterjee 	return 0;
85*857e71cbSNikhil Chatterjee }
86*857e71cbSNikhil Chatterjee 
87*857e71cbSNikhil Chatterjee char _license[] SEC("license") = "GPL";
88