brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 382bba7 Raw
137 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2024 Benjamin Tissoires3 */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_MICROSOFT 0x045e11#define PID_XBOX_ELITE_2 0x0b2212 13HID_BPF_CONFIG(14	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_MICROSOFT, PID_XBOX_ELITE_2)15);16 17/*18 * When using the Xbox Wireless Controller Elite 2 over Bluetooth,19 * the device exports the paddles on the back of the device as a single20 * bitfield value of usage "Assign Selection".21 *22 * The kernel doesn't process the paddles usage properly and reports KEY_UNKNOWN.23 *24 * SDL doesn't know how to interpret KEY_UNKNOWN and thus ignores the paddles.25 *26 * Given that over USB the kernel uses BTN_TRIGGER_HAPPY[5-8], we27 * can tweak the report descriptor to make the kernel interpret it properly:28 * - We need an application collection of gamepad (so we have to close the current29 *   Consumer Control one)30 * - We need to change the usage to be buttons from 0x15 to 0x1831 */32 33#define OFFSET_ASSIGN_SELECTION		21134#define ORIGINAL_RDESC_SIZE		46435 36const __u8 rdesc_assign_selection[] = {37	0x0a, 0x99, 0x00,              //   Usage (Media Select Security)     21138	0x15, 0x00,                    //   Logical Minimum (0)               21439	0x26, 0xff, 0x00,              //   Logical Maximum (255)             21640	0x95, 0x01,                    //   Report Count (1)                  21941	0x75, 0x04,                    //   Report Size (4)                   22142	0x81, 0x02,                    //   Input (Data,Var,Abs)              22343	0x15, 0x00,                    //   Logical Minimum (0)               22544	0x25, 0x00,                    //   Logical Maximum (0)               22745	0x95, 0x01,                    //   Report Count (1)                  22946	0x75, 0x04,                    //   Report Size (4)                   23147	0x81, 0x03,                    //   Input (Cnst,Var,Abs)              23348	0x0a, 0x81, 0x00,              //   Usage (Assign Selection)          23549	0x15, 0x00,                    //   Logical Minimum (0)               23850	0x26, 0xff, 0x00,              //   Logical Maximum (255)             24051	0x95, 0x01,                    //   Report Count (1)                  24352	0x75, 0x04,                    //   Report Size (4)                   24553	0x81, 0x02,                    //   Input (Data,Var,Abs)              24754};55 56/*57 * we replace the above report descriptor extract58 * with the one below.59 * To make things equal in size, we take out a larger60 * portion than just the "Assign Selection" range, because61 * we need to insert a new application collection to force62 * the kernel to use BTN_TRIGGER_HAPPY[4-7].63 */64const __u8 fixed_rdesc_assign_selection[] = {65	0x0a, 0x99, 0x00,              //   Usage (Media Select Security)     21166	0x15, 0x00,                    //   Logical Minimum (0)               21467	0x26, 0xff, 0x00,              //   Logical Maximum (255)             21668	0x95, 0x01,                    //   Report Count (1)                  21969	0x75, 0x04,                    //   Report Size (4)                   22170	0x81, 0x02,                    //   Input (Data,Var,Abs)              22371	/* 0x15, 0x00, */              //   Logical Minimum (0)               ignored72	0x25, 0x01,                    //   Logical Maximum (1)               22573	0x95, 0x04,                    //   Report Count (4)                  22774	0x75, 0x01,                    //   Report Size (1)                   22975	0x81, 0x03,                    //   Input (Cnst,Var,Abs)              23176	0xc0,                          //  End Collection                     23377	0x05, 0x01,                    //  Usage Page (Generic Desktop)       23478	0x0a, 0x05, 0x00,              //  Usage (Game Pad)                   23679	0xa1, 0x01,                    //  Collection (Application)           23980	0x05, 0x09,                    //   Usage Page (Button)               24181	0x19, 0x15,                    //   Usage Minimum (21)                24382	0x29, 0x18,                    //   Usage Maximum (24)                24583	/* 0x15, 0x00, */              //  Logical Minimum (0)                ignored84	/* 0x25, 0x01, */              //  Logical Maximum (1)                ignored85	/* 0x95, 0x01, */              //  Report Size (1)                    ignored86	/* 0x75, 0x04, */              //  Report Count (4)                   ignored87	0x81, 0x02,                    //   Input (Data,Var,Abs)              24788};89 90_Static_assert(sizeof(rdesc_assign_selection) == sizeof(fixed_rdesc_assign_selection),91	       "Rdesc and fixed rdesc of different size");92_Static_assert(sizeof(rdesc_assign_selection) + OFFSET_ASSIGN_SELECTION < ORIGINAL_RDESC_SIZE,93	       "Rdesc at given offset is too big");94 95SEC(HID_BPF_RDESC_FIXUP)96int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)97{98	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);99 100	if (!data)101		return 0; /* EPERM check */102 103	/* Check that the device is compatible */104	if (__builtin_memcmp(data + OFFSET_ASSIGN_SELECTION,105			     rdesc_assign_selection,106			     sizeof(rdesc_assign_selection)))107		return 0;108 109	__builtin_memcpy(data + OFFSET_ASSIGN_SELECTION,110			 fixed_rdesc_assign_selection,111			 sizeof(fixed_rdesc_assign_selection));112 113	return 0;114}115 116HID_BPF_OPS(xbox_elite_2) = {117	.hid_rdesc_fixup = (void *)hid_fix_rdesc,118};119 120SEC("syscall")121int probe(struct hid_bpf_probe_args *ctx)122{123	/* only bind to the keyboard interface */124	ctx->retval = ctx->rdesc_size != ORIGINAL_RDESC_SIZE;125	if (ctx->retval)126		ctx->retval = -EINVAL;127 128	if (__builtin_memcmp(ctx->rdesc + OFFSET_ASSIGN_SELECTION,129			     rdesc_assign_selection,130			     sizeof(rdesc_assign_selection)))131		ctx->retval = -EINVAL;132 133	return 0;134}135 136char _license[] SEC("license") = "GPL";137