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 */
SEC(HID_BPF_RDESC_FIXUP)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 */
SEC(HID_BPF_DEVICE_EVENT)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")
probe(struct hid_bpf_probe_args * ctx)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