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