summaryrefslogtreecommitdiff
path: root/drivers/hid/bpf/progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c
blob: ecf775a99346454718b2176481a443f6734f6d01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2024 Kumar Swarnam Iyer (kumar.s.iyer65@gmail.com)
 */

#include "vmlinux.h"
#include "hid_bpf.h"
#include "hid_bpf_helpers.h"
#include <bpf/bpf_tracing.h>

#define VID_THRUSTMASTER 0x044F
#define PID_TCA_YOKE_BOEING 0x0409

HID_BPF_CONFIG(
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_THRUSTMASTER, PID_TCA_YOKE_BOEING)
);

/*  The original HID descriptor of the Thrustmaster TCA Yoke Boeing joystick contains
 *  an Input field that shows up as an axis, ABS_MISC in Linux. But it is not possible
 *  to assign an actual physical control to this axis as they're all taken up. There
 *  are 2 vendor-defined inputs where the Input type appears to be defined wrongly.
 *  This bpf attempts to fix this by changing the Inputs so that it doesn't show up in
 *  Linux at all.
 *  This version is the short version fix that only changes 2 fields in the descriptor
 *  instead of the whole report descriptor.
 *  For reference, this is the original report descriptor:
 *
 *  0x05, 0x01,                    // Usage Page (Generic Desktop)        0
 *  0x09, 0x04,                    // Usage (Joystick)                    2
 *  0xa1, 0x01,                    // Collection (Application)            4
 *  0x85, 0x01,                    //  Report ID (1)                      6
 *  0x09, 0x39,                    //  Usage (Hat switch)                 8
 *  0x15, 0x00,                    //  Logical Minimum (0)                10
 *  0x25, 0x07,                    //  Logical Maximum (7)                12
 *  0x35, 0x00,                    //  Physical Minimum (0)               14
 *  0x46, 0x3b, 0x01,              //  Physical Maximum (315)             16
 *  0x65, 0x14,                    //  Unit (EnglishRotation: deg)        19
 *  0x75, 0x04,                    //  Report Size (4)                    21
 *  0x95, 0x01,                    //  Report Count (1)                   23
 *  0x81, 0x42,                    //  Input (Data,Var,Abs,Null)          25
 *  0x65, 0x00,                    //  Unit (None)                        27
 *  0x05, 0x09,                    //  Usage Page (Button)                29
 *  0x19, 0x01,                    //  Usage Minimum (1)                  31
 *  0x29, 0x12,                    //  Usage Maximum (18)                 33
 *  0x15, 0x00,                    //  Logical Minimum (0)                35
 *  0x25, 0x01,                    //  Logical Maximum (1)                37
 *  0x75, 0x01,                    //  Report Size (1)                    39
 *  0x95, 0x12,                    //  Report Count (18)                  41
 *  0x81, 0x02,                    //  Input (Data,Var,Abs)               43
 *  0x95, 0x02,                    //  Report Count (2)                   45
 *  0x81, 0x03,                    //  Input (Cnst,Var,Abs)               47
 *  0x05, 0x01,                    //  Usage Page (Generic Desktop)       49
 *  0x09, 0x31,                    //  Usage (Y)                          51
 *  0x09, 0x30,                    //  Usage (X)                          53
 *  0x09, 0x32,                    //  Usage (Z)                          55
 *  0x09, 0x34,                    //  Usage (Ry)                         57
 *  0x09, 0x33,                    //  Usage (Rx)                         59
 *  0x09, 0x35,                    //  Usage (Rz)                         61
 *  0x15, 0x00,                    //  Logical Minimum (0)                63
 *  0x27, 0xff, 0xff, 0x00, 0x00,  //  Logical Maximum (65535)            65
 *  0x75, 0x10,                    //  Report Size (16)                   70
 *  0x95, 0x06,                    //  Report Count (6)                   72
 *  0x81, 0x02,                    //  Input (Data,Var,Abs)               74
 *  0x06, 0xf0, 0xff,              //  Usage Page (Vendor Usage Page 0xfff0) 76
 *  0x09, 0x59,                    //  Usage (Vendor Usage 0x59)          79
 *  0x15, 0x00,                    //  Logical Minimum (0)                81
 *  0x26, 0xff, 0x00,              //  Logical Maximum (255)              83
 *  0x75, 0x08,                    //  Report Size (8)                    86
 *  0x95, 0x01,                    //  Report Count (1)                   88
 *  0x81, 0x02,                    //  Input (Data,Var,Abs)               90 --> Needs to be changed
 *  0x09, 0x51,                    //  Usage (Vendor Usage 0x51)          92
 *  0x15, 0x00,                    //  Logical Minimum (0)                94
 *  0x26, 0xff, 0x00,              //  Logical Maximum (255)              96
 *  0x75, 0x08,                    //  Report Size (8)                    99
 *  0x95, 0x20,                    //  Report Count (32)                  101 --> Needs to be changed
 *  0x81, 0x02,                    //  Input (Data,Var,Abs)               103
 *  0x09, 0x50,                    //  Usage (Vendor Usage 0x50)          105
 *  0x15, 0x00,                    //  Logical Minimum (0)                107
 *  0x26, 0xff, 0x00,              //  Logical Maximum (255)              109
 *  0x75, 0x08,                    //  Report Size (8)                    112
 *  0x95, 0x0f,                    //  Report Count (15)                  114
 *  0x81, 0x03,                    //  Input (Cnst,Var,Abs)               116
 *  0x09, 0x47,                    //  Usage (Vendor Usage 0x47)          118
 *  0x85, 0xf2,                    //  Report ID (242)                    120
 *  0x15, 0x00,                    //  Logical Minimum (0)                122
 *  0x26, 0xff, 0x00,              //  Logical Maximum (255)              124
 *  0x75, 0x08,                    //  Report Size (8)                    127
 *  0x95, 0x3f,                    //  Report Count (63)                  129
 *  0xb1, 0x02,                    //  Feature (Data,Var,Abs)             131
 *  0x09, 0x48,                    //  Usage (Vendor Usage 0x48)          133
 *  0x85, 0xf3,                    //  Report ID (243)                    135
 *  0x15, 0x00,                    //  Logical Minimum (0)                137
 *  0x26, 0xff, 0x00,              //  Logical Maximum (255)              139
 *  0x75, 0x08,                    //  Report Size (8)                    142
 *  0x95, 0x3f,                    //  Report Count (63)                  144
 *  0xb1, 0x02,                    //  Feature (Data,Var,Abs)             146
 *  0xc0,                          // End Collection                      148
 */

SEC(HID_BPF_RDESC_FIXUP)
int BPF_PROG(hid_fix_rdesc_tca_yoke, struct hid_bpf_ctx *hctx)
{
	const int expected_length = 148;

	if (hctx->size != expected_length)
		return 0;

	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);

	if (!data)
		return 0; /* EPERM */

	/* Safety check, our probe() should take care of this though */
	if (data[1] != 0x01 /* Generic Desktop */ || data[3] != 0x04 /* Joystick */)
		return 0;

	/* The report descriptor sets incorrect Input items in 2 places, resulting in a
	 * non-existing axis showing up.
	 * This change sets the correct Input which prevents the axis from showing up in Linux.
	 */

	if (data[90] == 0x81 && /* Input */
	    data[103] == 0x81) { /* Input */
		data[91] = 0x03; /* Input set to 0x03 Constant, Variable Absolute */
		data[104] = 0x03; /* Input set to 0X03 Constant, Variable Absolute */
	}

	return 0;
}

HID_BPF_OPS(tca_yoke) = {
	.hid_rdesc_fixup = (void *)hid_fix_rdesc_tca_yoke,
};

SEC("syscall")
int probe(struct hid_bpf_probe_args *ctx)
{
	/* ensure the kernel isn't fixed already */
	if (ctx->rdesc[91] != 0x02) /* Input for 0x59 Usage type has changed */
		ctx->retval = -EINVAL;

	return 0;
}

char _license[] SEC("license") = "GPL";