xref: /linux/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2024 Benjamin Tissoires
3  */
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_BETOP_2185PC        0x11C0
11 #define PID_RAPTOR_MACH_2 0x5606
12 
13 HID_BPF_CONFIG(
14 	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_BETOP_2185PC, PID_RAPTOR_MACH_2),
15 );
16 
17 /*
18  * For reference, this is the fixed report descriptor
19  *
20  * static const __u8 fixed_rdesc[] = {
21  *     0x05, 0x01,                    // Usage Page (Generic Desktop)        0
22  *     0x09, 0x04,                    // Usage (Joystick)                    2
23  *     0xa1, 0x01,                    // Collection (Application)            4
24  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       6
25  *     0x85, 0x01,                    //  Report ID (1)                      8
26  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       10
27  *     0x09, 0x30,                    //  Usage (X)                          12
28  *     0x75, 0x10,                    //  Report Size (16)                   14
29  *     0x95, 0x01,                    //  Report Count (1)                   16
30  *     0x15, 0x00,                    //  Logical Minimum (0)                18
31  *     0x26, 0xff, 0x07,              //  Logical Maximum (2047)             20
32  *     0x46, 0xff, 0x07,              //  Physical Maximum (2047)            23
33  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               26
34  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       28
35  *     0x09, 0x31,                    //  Usage (Y)                          30
36  *     0x75, 0x10,                    //  Report Size (16)                   32
37  *     0x95, 0x01,                    //  Report Count (1)                   34
38  *     0x15, 0x00,                    //  Logical Minimum (0)                36
39  *     0x26, 0xff, 0x07,              //  Logical Maximum (2047)             38
40  *     0x46, 0xff, 0x07,              //  Physical Maximum (2047)            41
41  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               44
42  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       46
43  *     0x09, 0x33,                    //  Usage (Rx)                         48
44  *     0x75, 0x10,                    //  Report Size (16)                   50
45  *     0x95, 0x01,                    //  Report Count (1)                   52
46  *     0x15, 0x00,                    //  Logical Minimum (0)                54
47  *     0x26, 0xff, 0x03,              //  Logical Maximum (1023)             56
48  *     0x46, 0xff, 0x03,              //  Physical Maximum (1023)            59
49  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               62
50  *     0x05, 0x00,                    //  Usage Page (Undefined)             64
51  *     0x09, 0x00,                    //  Usage (Undefined)                  66
52  *     0x75, 0x10,                    //  Report Size (16)                   68
53  *     0x95, 0x01,                    //  Report Count (1)                   70
54  *     0x15, 0x00,                    //  Logical Minimum (0)                72
55  *     0x26, 0xff, 0x03,              //  Logical Maximum (1023)             74
56  *     0x46, 0xff, 0x03,              //  Physical Maximum (1023)            77
57  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               80
58  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       82
59  *     0x09, 0x32,                    //  Usage (Z)                          84
60  *     0x75, 0x10,                    //  Report Size (16)                   86
61  *     0x95, 0x01,                    //  Report Count (1)                   88
62  *     0x15, 0x00,                    //  Logical Minimum (0)                90
63  *     0x26, 0xff, 0x03,              //  Logical Maximum (1023)             92
64  *     0x46, 0xff, 0x03,              //  Physical Maximum (1023)            95
65  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               98
66  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       100
67  *     0x09, 0x35,                    //  Usage (Rz)                         102
68  *     0x75, 0x10,                    //  Report Size (16)                   104
69  *     0x95, 0x01,                    //  Report Count (1)                   106
70  *     0x15, 0x00,                    //  Logical Minimum (0)                108
71  *     0x26, 0xff, 0x03,              //  Logical Maximum (1023)             110
72  *     0x46, 0xff, 0x03,              //  Physical Maximum (1023)            113
73  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               116
74  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       118
75  *     0x09, 0x34,                    //  Usage (Ry)                         120
76  *     0x75, 0x10,                    //  Report Size (16)                   122
77  *     0x95, 0x01,                    //  Report Count (1)                   124
78  *     0x15, 0x00,                    //  Logical Minimum (0)                126
79  *     0x26, 0xff, 0x07,              //  Logical Maximum (2047)             128
80  *     0x46, 0xff, 0x07,              //  Physical Maximum (2047)            131
81  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               134
82  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       136
83  *     0x09, 0x36,                    //  Usage (Slider)                     138
84  *     0x75, 0x10,                    //  Report Size (16)                   140
85  *     0x95, 0x01,                    //  Report Count (1)                   142
86  *     0x15, 0x00,                    //  Logical Minimum (0)                144
87  *     0x26, 0xff, 0x03,              //  Logical Maximum (1023)             146
88  *     0x46, 0xff, 0x03,              //  Physical Maximum (1023)            149
89  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               152
90  *     0x05, 0x09,                    //  Usage Page (Button)                154
91  *     0x19, 0x01,                    //  Usage Minimum (1)                  156
92  *     0x2a, 0x1d, 0x00,              //  Usage Maximum (29)                 158
93  *     0x15, 0x00,                    //  Logical Minimum (0)                161
94  *     0x25, 0x01,                    //  Logical Maximum (1)                163
95  *     0x75, 0x01,                    //  Report Size (1)                    165
96  *     0x96, 0x80, 0x00,              //  Report Count (128)                 167
97  *     0x81, 0x02,                    //  Input (Data,Var,Abs)               170
98  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       172
99  *     0x09, 0x39,                    //  Usage (Hat switch)                 174
100  *     0x26, 0x07, 0x00,              //  Logical Maximum (7)                176 // changed (was 239)
101  *     0x46, 0x68, 0x01,              //  Physical Maximum (360)             179
102  *     0x65, 0x14,                    //  Unit (EnglishRotation: deg)        182
103  *     0x75, 0x10,                    //  Report Size (16)                   184
104  *     0x95, 0x01,                    //  Report Count (1)                   186
105  *     0x81, 0x42,                    //  Input (Data,Var,Abs,Null)          188
106  *     0x05, 0x01,                    //  Usage Page (Generic Desktop)       190
107  *     0x09, 0x00,                    //  Usage (Undefined)                  192
108  *     0x75, 0x08,                    //  Report Size (8)                    194
109  *     0x95, 0x1d,                    //  Report Count (29)                  196
110  *     0x81, 0x01,                    //  Input (Cnst,Arr,Abs)               198
111  *     0x15, 0x00,                    //  Logical Minimum (0)                200
112  *     0x26, 0xef, 0x00,              //  Logical Maximum (239)              202
113  *     0x85, 0x58,                    //  Report ID (88)                     205
114  *     0x26, 0xff, 0x00,              //  Logical Maximum (255)              207
115  *     0x46, 0xff, 0x00,              //  Physical Maximum (255)             210
116  *     0x75, 0x08,                    //  Report Size (8)                    213
117  *     0x95, 0x3f,                    //  Report Count (63)                  215
118  *     0x09, 0x00,                    //  Usage (Undefined)                  217
119  *     0x91, 0x02,                    //  Output (Data,Var,Abs)              219
120  *     0x85, 0x59,                    //  Report ID (89)                     221
121  *     0x75, 0x08,                    //  Report Size (8)                    223
122  *     0x95, 0x80,                    //  Report Count (128)                 225
123  *     0x09, 0x00,                    //  Usage (Undefined)                  227
124  *     0xb1, 0x02,                    //  Feature (Data,Var,Abs)             229
125  *     0xc0,                          // End Collection                      231
126  * };
127  */
128 
129 /*
130  * We need to amend the report descriptor for the following:
131  * - the joystick sends its hat_switch data between 0 and 239 but
132  *   the kernel expects the logical max to stick into a signed 8 bits
133  *   integer. We thus divide it by 30 to match what other joysticks are
134  *   doing
135  */
136 SEC(HID_BPF_RDESC_FIXUP)
137 int BPF_PROG(hid_fix_rdesc_raptor_mach_2, struct hid_bpf_ctx *hctx)
138 {
139 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
140 
141 	if (!data)
142 		return 0; /* EPERM check */
143 
144 	data[177] = 0x07;
145 
146 	return 0;
147 }
148 
149 /*
150  * The hat_switch value at offsets 33 and 34 (16 bits) needs
151  * to be reduced to a single 8 bit signed integer. So we
152  * divide it by 30.
153  * Byte 34 is always null, so it is ignored.
154  */
155 SEC(HID_BPF_DEVICE_EVENT)
156 int BPF_PROG(raptor_mach_2_fix_hat_switch, struct hid_bpf_ctx *hctx)
157 {
158 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 64 /* size */);
159 
160 	if (!data)
161 		return 0; /* EPERM check */
162 
163 	if (data[0] != 0x01) /* not the joystick report ID */
164 		return 0;
165 
166 	data[33] /= 30;
167 
168 	return 0;
169 }
170 
171 HID_BPF_OPS(raptor_mach_2) = {
172 	.hid_rdesc_fixup = (void *)hid_fix_rdesc_raptor_mach_2,
173 	.hid_device_event = (void *)raptor_mach_2_fix_hat_switch,
174 };
175 
176 SEC("syscall")
177 int probe(struct hid_bpf_probe_args *ctx)
178 {
179 	ctx->retval = ctx->rdesc_size != 232;
180 	if (ctx->retval)
181 		ctx->retval = -EINVAL;
182 
183 	/* ensure the kernel isn't fixed already */
184 	if (ctx->rdesc[177] != 0xef) /* Logical Max of 239 */
185 		ctx->retval = -EINVAL;
186 
187 	return 0;
188 }
189 
190 char _license[] SEC("license") = "GPL";
191