Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: bpf: add in-tree HID-BPF fix for the Raptor Mach 2

This device is already fixed by "HID: do not assume HAT Switch
logical max < 8", but for people without the fix already, having the
HID-BPF locally can fix the device while they wait for their
distribution to update.

Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-9-a8bf16033ef8@kernel.org
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

+185
+185
drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c
··· 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("fmod_ret/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("fmod_ret/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 + SEC("syscall") 172 + int probe(struct hid_bpf_probe_args *ctx) 173 + { 174 + ctx->retval = ctx->rdesc_size != 232; 175 + if (ctx->retval) 176 + ctx->retval = -EINVAL; 177 + 178 + /* ensure the kernel isn't fixed already */ 179 + if (ctx->rdesc[177] != 0xef) /* Logical Max of 239 */ 180 + ctx->retval = -EINVAL; 181 + 182 + return 0; 183 + } 184 + 185 + char _license[] SEC("license") = "GPL";