Merge branch 'for-6.13/bpf' into for-linus

- improvement of the way hid-bpf coexists with specific drivers (others than
  hid-generic) that are already bound to devices (Benjamin Tissoires)
This commit is contained in:
Jiri Kosina
2024-11-18 22:02:17 +01:00
17 changed files with 708 additions and 201 deletions
+6 -3
View File
@@ -148,7 +148,7 @@ out:
}
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_output_report);
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size)
const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size)
{
int ret;
struct hid_bpf_ctx_kern ctx_kern = {
@@ -183,7 +183,7 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned
ignore_bpf:
kfree(ctx_kern.data);
return kmemdup(rdesc, *size, GFP_KERNEL);
return rdesc;
}
EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
@@ -260,8 +260,11 @@ int hid_bpf_allocate_event_data(struct hid_device *hdev)
int hid_bpf_reconnect(struct hid_device *hdev)
{
if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status))
if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) {
/* trigger call to call_hid_bpf_rdesc_fixup() during the next probe */
hdev->bpf_rsize = 0;
return device_reprobe(&hdev->dev);
}
return 0;
}
+1
View File
@@ -79,6 +79,7 @@ static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log,
WRITE_RANGE(hid_device, name, true),
WRITE_RANGE(hid_device, uniq, true),
WRITE_RANGE(hid_device, phys, true),
WRITE_RANGE(hid_device, quirks, false),
};
#undef WRITE_RANGE
const struct btf_type *state = NULL;
+44 -22
View File
@@ -214,7 +214,8 @@ static const __u8 fixed_rdesc_pad[] = {
CollectionApplication(
// -- Byte 0 in report
ReportId(PAD_REPORT_ID)
LogicalRange_i8(0, 1)
LogicalMaximum_i8(0)
LogicalMaximum_i8(1)
UsagePage_Digitizers
Usage_Dig_TabletFunctionKeys
CollectionPhysical(
@@ -234,14 +235,17 @@ static const __u8 fixed_rdesc_pad[] = {
Input(Var|Abs)
// Byte 4 in report is the dial
Usage_GD_Wheel
LogicalRange_i8(-1, 1)
LogicalMinimum_i8(-1)
LogicalMaximum_i8(1)
ReportCount(1)
ReportSize(8)
Input(Var|Rel)
// Byte 5 is the button state
UsagePage_Button
UsageRange_i8(0x01, 0x8)
LogicalRange_i8(0x0, 0x1)
UsageMinimum_i8(0x01)
UsageMaximum_i8(0x08)
LogicalMinimum_i8(0x0)
LogicalMaximum_i8(0x1)
ReportCount(7)
ReportSize(1)
Input(Var|Abs)
@@ -265,7 +269,8 @@ static const __u8 fixed_rdesc_pen[] = {
Usage_Dig_TipSwitch
Usage_Dig_BarrelSwitch
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
ReportSize(1)
ReportCount(3)
Input(Var|Abs)
@@ -280,22 +285,28 @@ static const __u8 fixed_rdesc_pen[] = {
UsagePage_GenericDesktop
Unit(cm)
UnitExponent(-1)
PhysicalRange_i16(0, 266)
LogicalRange_i16(0, 32767)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(266)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32767)
Usage_GD_X
Input(Var|Abs) // Bytes 2+3
PhysicalRange_i16(0, 166)
LogicalRange_i16(0, 32767)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(166)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32767)
Usage_GD_Y
Input(Var|Abs) // Bytes 4+5
)
UsagePage_Digitizers
Usage_Dig_TipPressure
LogicalRange_i16(0, 8191)
LogicalMinimum_i16(0)
LogicalMaximum_i16(8191)
Input(Var|Abs) // Byte 6+7
ReportSize(8)
ReportCount(2)
LogicalRange_i8(-60, 60)
LogicalMinimum_i8(-60)
LogicalMaximum_i8(60)
Usage_Dig_XTilt
Usage_Dig_YTilt
Input(Var|Abs) // Byte 8+9
@@ -313,7 +324,8 @@ static const __u8 fixed_rdesc_vendor[] = {
Usage_Dig_Pen
CollectionPhysical(
// Byte 1 are the buttons
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
ReportSize(1)
Usage_Dig_TipSwitch
Usage_Dig_BarrelSwitch
@@ -333,25 +345,31 @@ static const __u8 fixed_rdesc_vendor[] = {
UnitExponent(-1)
// Note: reported logical range differs
// from the pen report ID for x and y
LogicalRange_i16(0, 53340)
PhysicalRange_i16(0, 266)
LogicalMinimum_i16(0)
LogicalMaximum_i16(53340)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(266)
// Bytes 2/3 in report
Usage_GD_X
Input(Var|Abs)
LogicalRange_i16(0, 33340)
PhysicalRange_i16(0, 166)
LogicalMinimum_i16(0)
LogicalMaximum_i16(33340)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(166)
// Bytes 4/5 in report
Usage_GD_Y
Input(Var|Abs)
)
// Bytes 6/7 in report
LogicalRange_i16(0, 8191)
LogicalMinimum_i16(0)
LogicalMaximum_i16(8191)
Usage_Dig_TipPressure
Input(Var|Abs)
// Bytes 8/9 in report
ReportCount(1) // Padding
Input(Const)
LogicalRange_i8(-60, 60)
LogicalMinimum_i8(-60)
LogicalMaximum_i8(60)
// Byte 10 in report
Usage_Dig_XTilt
// Byte 11 in report
@@ -366,7 +384,8 @@ static const __u8 fixed_rdesc_vendor[] = {
CollectionApplication(
// Byte 0
ReportId(PAD_REPORT_ID)
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
UsagePage_Digitizers
Usage_Dig_TabletFunctionKeys
CollectionPhysical(
@@ -386,15 +405,18 @@ static const __u8 fixed_rdesc_vendor[] = {
Input(Var|Abs)
// Byte 4 is the button state
UsagePage_Button
UsageRange_i8(0x01, 0x8)
LogicalRange_i8(0x0, 0x1)
UsageMinimum_i8(0x1)
UsageMaximum_i8(0x8)
LogicalMinimum_i8(0x0)
LogicalMaximum_i8(0x1)
ReportCount(8)
ReportSize(1)
Input(Var|Abs)
// Byte 5 is the top dial
UsagePage_GenericDesktop
Usage_GD_Wheel
LogicalRange_i8(-1, 1)
LogicalMinimum_i8(-1)
LogicalMaximum_i8(1)
ReportCount(1)
ReportSize(8)
Input(Var|Rel)
+40 -20
View File
@@ -170,7 +170,8 @@ static const __u8 fixed_rdesc_pad[] = {
CollectionApplication(
// -- Byte 0 in report
ReportId(PAD_REPORT_ID)
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
UsagePage_Digitizers
Usage_Dig_TabletFunctionKeys
CollectionPhysical(
@@ -190,14 +191,17 @@ static const __u8 fixed_rdesc_pad[] = {
Input(Var|Abs)
// Byte 4 in report is the wheel
Usage_GD_Wheel
LogicalRange_i8(-1, 1)
LogicalMinimum_i8(-1)
LogicalMaximum_i8(1)
ReportCount(1)
ReportSize(8)
Input(Var|Rel)
// Byte 5 is the button state
UsagePage_Button
UsageRange_i8(0x01, 0x6)
LogicalRange_i8(0x01, 0x6)
UsageMinimum_i8(0x1)
UsageMaximum_i8(0x6)
LogicalMinimum_i8(0x1)
LogicalMaximum_i8(0x6)
ReportCount(1)
ReportSize(8)
Input(Arr|Abs)
@@ -219,7 +223,8 @@ static const __u8 fixed_rdesc_pen[] = {
Usage_Dig_TipSwitch
Usage_Dig_BarrelSwitch
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
ReportSize(1)
ReportCount(3)
Input(Var|Abs)
@@ -234,18 +239,23 @@ static const __u8 fixed_rdesc_pen[] = {
UsagePage_GenericDesktop
Unit(cm)
UnitExponent(-1)
PhysicalRange_i16(0, 160)
LogicalRange_i16(0, 32767)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(160)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32767)
Usage_GD_X
Input(Var|Abs) // Bytes 2+3
PhysicalRange_i16(0, 100)
LogicalRange_i16(0, 32767)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(100)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32767)
Usage_GD_Y
Input(Var|Abs) // Bytes 4+5
)
UsagePage_Digitizers
Usage_Dig_TipPressure
LogicalRange_i16(0, 8191)
LogicalMinimum_i16(0)
LogicalMaximum_i16(8191)
Input(Var|Abs) // Byte 6+7
// Two bytes padding so we don't need to change the report at all
ReportSize(8)
@@ -265,7 +275,8 @@ static const __u8 fixed_rdesc_vendor[] = {
Usage_Dig_Pen
CollectionPhysical(
// Byte 1 are the buttons
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
ReportSize(1)
Usage_Dig_TipSwitch
Usage_Dig_BarrelSwitch
@@ -285,19 +296,24 @@ static const __u8 fixed_rdesc_vendor[] = {
UnitExponent(-1)
// Note: reported logical range differs
// from the pen report ID for x and y
LogicalRange_i16(0, 32000)
PhysicalRange_i16(0, 160)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32000)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(160)
// Bytes 2/3 in report
Usage_GD_X
Input(Var|Abs)
LogicalRange_i16(0, 20000)
PhysicalRange_i16(0, 100)
LogicalMinimum_i16(0)
LogicalMaximum_i16(20000)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(100)
// Bytes 4/5 in report
Usage_GD_Y
Input(Var|Abs)
)
// Bytes 6/7 in report
LogicalRange_i16(0, 8192)
LogicalMinimum_i16(0)
LogicalMaximum_i16(8192)
Usage_Dig_TipPressure
Input(Var|Abs)
)
@@ -307,7 +323,8 @@ static const __u8 fixed_rdesc_vendor[] = {
CollectionApplication(
// Byte 0
ReportId(PAD_REPORT_ID)
LogicalRange_i8(0, 1)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
UsagePage_Digitizers
Usage_Dig_TabletFunctionKeys
CollectionPhysical(
@@ -327,8 +344,10 @@ static const __u8 fixed_rdesc_vendor[] = {
Input(Var|Abs)
// Byte 4 is the button state
UsagePage_Button
UsageRange_i8(0x01, 0x6)
LogicalRange_i8(0x0, 0x1)
UsageMinimum_i8(0x1)
UsageMaximum_i8(0x6)
LogicalMinimum_i8(0x0)
LogicalMaximum_i8(0x1)
ReportCount(6)
ReportSize(1)
Input(Var|Abs)
@@ -337,7 +356,8 @@ static const __u8 fixed_rdesc_vendor[] = {
// Byte 5 is the wheel
UsagePage_GenericDesktop
Usage_GD_Wheel
LogicalRange_i8(-1, 1)
LogicalMinimum_i8(-1)
LogicalMaximum_i8(1)
ReportCount(1)
ReportSize(8)
Input(Var|Rel)
+154
View File
@@ -0,0 +1,154 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 Tatsuyuki Ishi
*/
#include "vmlinux.h"
#include "hid_bpf.h"
#include "hid_bpf_helpers.h"
#include <bpf/bpf_tracing.h>
#define VID_HOLTEK 0x04D9
#define PID_MD770 0x0339
#define RDESC_SIZE 203
HID_BPF_CONFIG(
HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HOLTEK, PID_MD770)
);
/*
* The Mistel MD770 keyboard reports the first 6 simultaneous key presses
* through the first interface, and anything beyond that through a second
* interface. Unfortunately, the second interface's report descriptor has an
* error, causing events to be malformed and ignored. This HID-BPF driver
* fixes the descriptor to allow NKRO to work again.
*
* For reference, this is the original report descriptor:
*
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
* 0x09, 0x80, // Usage (System Control) 2
* 0xa1, 0x01, // Collection (Application) 4
* 0x85, 0x01, // Report ID (1) 6
* 0x19, 0x81, // Usage Minimum (129) 8
* 0x29, 0x83, // Usage Maximum (131) 10
* 0x15, 0x00, // Logical Minimum (0) 12
* 0x25, 0x01, // Logical Maximum (1) 14
* 0x95, 0x03, // Report Count (3) 16
* 0x75, 0x01, // Report Size (1) 18
* 0x81, 0x02, // Input (Data,Var,Abs) 20
* 0x95, 0x01, // Report Count (1) 22
* 0x75, 0x05, // Report Size (5) 24
* 0x81, 0x01, // Input (Cnst,Arr,Abs) 26
* 0xc0, // End Collection 28
* 0x05, 0x0c, // Usage Page (Consumer Devices) 29
* 0x09, 0x01, // Usage (Consumer Control) 31
* 0xa1, 0x01, // Collection (Application) 33
* 0x85, 0x02, // Report ID (2) 35
* 0x15, 0x00, // Logical Minimum (0) 37
* 0x25, 0x01, // Logical Maximum (1) 39
* 0x95, 0x12, // Report Count (18) 41
* 0x75, 0x01, // Report Size (1) 43
* 0x0a, 0x83, 0x01, // Usage (AL Consumer Control Config) 45
* 0x0a, 0x8a, 0x01, // Usage (AL Email Reader) 48
* 0x0a, 0x92, 0x01, // Usage (AL Calculator) 51
* 0x0a, 0x94, 0x01, // Usage (AL Local Machine Browser) 54
* 0x09, 0xcd, // Usage (Play/Pause) 57
* 0x09, 0xb7, // Usage (Stop) 59
* 0x09, 0xb6, // Usage (Scan Previous Track) 61
* 0x09, 0xb5, // Usage (Scan Next Track) 63
* 0x09, 0xe2, // Usage (Mute) 65
* 0x09, 0xea, // Usage (Volume Down) 67
* 0x09, 0xe9, // Usage (Volume Up) 69
* 0x0a, 0x21, 0x02, // Usage (AC Search) 71
* 0x0a, 0x23, 0x02, // Usage (AC Home) 74
* 0x0a, 0x24, 0x02, // Usage (AC Back) 77
* 0x0a, 0x25, 0x02, // Usage (AC Forward) 80
* 0x0a, 0x26, 0x02, // Usage (AC Stop) 83
* 0x0a, 0x27, 0x02, // Usage (AC Refresh) 86
* 0x0a, 0x2a, 0x02, // Usage (AC Bookmarks) 89
* 0x81, 0x02, // Input (Data,Var,Abs) 92
* 0x95, 0x01, // Report Count (1) 94
* 0x75, 0x0e, // Report Size (14) 96
* 0x81, 0x01, // Input (Cnst,Arr,Abs) 98
* 0xc0, // End Collection 100
* 0x05, 0x01, // Usage Page (Generic Desktop) 101
* 0x09, 0x02, // Usage (Mouse) 103
* 0xa1, 0x01, // Collection (Application) 105
* 0x09, 0x01, // Usage (Pointer) 107
* 0xa1, 0x00, // Collection (Physical) 109
* 0x85, 0x03, // Report ID (3) 111
* 0x05, 0x09, // Usage Page (Button) 113
* 0x19, 0x01, // Usage Minimum (1) 115
* 0x29, 0x08, // Usage Maximum (8) 117
* 0x15, 0x00, // Logical Minimum (0) 119
* 0x25, 0x01, // Logical Maximum (1) 121
* 0x75, 0x01, // Report Size (1) 123
* 0x95, 0x08, // Report Count (8) 125
* 0x81, 0x02, // Input (Data,Var,Abs) 127
* 0x05, 0x01, // Usage Page (Generic Desktop) 129
* 0x09, 0x30, // Usage (X) 131
* 0x09, 0x31, // Usage (Y) 133
* 0x16, 0x01, 0x80, // Logical Minimum (-32767) 135
* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 138
* 0x75, 0x10, // Report Size (16) 141
* 0x95, 0x02, // Report Count (2) 143
* 0x81, 0x06, // Input (Data,Var,Rel) 145
* 0x09, 0x38, // Usage (Wheel) 147
* 0x15, 0x81, // Logical Minimum (-127) 149
* 0x25, 0x7f, // Logical Maximum (127) 151
* 0x75, 0x08, // Report Size (8) 153
* 0x95, 0x01, // Report Count (1) 155
* 0x81, 0x06, // Input (Data,Var,Rel) 157
* 0x05, 0x0c, // Usage Page (Consumer Devices) 159
* 0x0a, 0x38, 0x02, // Usage (AC Pan) 161
* 0x95, 0x01, // Report Count (1) 164
* 0x81, 0x06, // Input (Data,Var,Rel) 166
* 0xc0, // End Collection 168
* 0xc0, // End Collection 169
* 0x05, 0x01, // Usage Page (Generic Desktop) 170
* 0x09, 0x06, // Usage (Keyboard) 172
* 0xa1, 0x01, // Collection (Application) 174
* 0x85, 0x04, // Report ID (4) 176
* 0x05, 0x07, // Usage Page (Keyboard) 178
* 0x95, 0x01, // Report Count (1) 180
* 0x75, 0x08, // Report Size (8) 182
* 0x81, 0x03, // Input (Cnst,Var,Abs) 184
* 0x95, 0xe8, // Report Count (232) 186
* 0x75, 0x01, // Report Size (1) 188
* 0x15, 0x00, // Logical Minimum (0) 190
* 0x25, 0x01, // Logical Maximum (1) 192
* 0x05, 0x07, // Usage Page (Keyboard) 194
* 0x19, 0x00, // Usage Minimum (0) 196
* 0x29, 0xe7, // Usage Maximum (231) 198
* 0x81, 0x00, // Input (Data,Arr,Abs) 200 <- change to 0x81, 0x02 (Data,Var,Abs)
* 0xc0, // End Collection 202
*/
SEC(HID_BPF_RDESC_FIXUP)
int BPF_PROG(hid_rdesc_fixup_mistel_md770, struct hid_bpf_ctx *hctx)
{
__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
if (!data)
return 0; /* EPERM check */
if (data[201] == 0x00)
data[201] = 0x02;
return 0;
}
HID_BPF_OPS(mistel_md770) = {
.hid_rdesc_fixup = (void *)hid_rdesc_fixup_mistel_md770,
};
SEC("syscall")
int probe(struct hid_bpf_probe_args *ctx)
{
ctx->retval = ctx->rdesc_size != RDESC_SIZE;
if (ctx->retval)
ctx->retval = -EINVAL;
return 0;
}
char _license[] SEC("license") = "GPL";
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2024 José Expósito
*/
#include "vmlinux.h"
#include "hid_bpf.h"
#include "hid_bpf_helpers.h"
#include <bpf/bpf_tracing.h>
#define VID_RAPOO 0x24AE
#define PID_M50 0x2015
#define RDESC_SIZE 186
HID_BPF_CONFIG(
HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_RAPOO, PID_M50)
);
/*
* The Rapoo M50 Plus Silent mouse has 2 side buttons in addition to the left,
* right and middle buttons. However, its original HID descriptor has a Usage
* Maximum of 3, preventing the side buttons to work. This HID-BPF driver
* changes that usage to 5.
*
* For reference, this is the original report descriptor:
*
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
* 0x09, 0x02, // Usage (Mouse) 2
* 0xa1, 0x01, // Collection (Application) 4
* 0x85, 0x01, // Report ID (1) 6
* 0x09, 0x01, // Usage (Pointer) 8
* 0xa1, 0x00, // Collection (Physical) 10
* 0x05, 0x09, // Usage Page (Button) 12
* 0x19, 0x01, // Usage Minimum (1) 14
* 0x29, 0x03, // Usage Maximum (3) 16 <- change to 0x05
* 0x15, 0x00, // Logical Minimum (0) 18
* 0x25, 0x01, // Logical Maximum (1) 20
* 0x75, 0x01, // Report Size (1) 22
* 0x95, 0x05, // Report Count (5) 24
* 0x81, 0x02, // Input (Data,Var,Abs) 26
* 0x75, 0x03, // Report Size (3) 28
* 0x95, 0x01, // Report Count (1) 30
* 0x81, 0x01, // Input (Cnst,Arr,Abs) 32
* 0x05, 0x01, // Usage Page (Generic Desktop) 34
* 0x09, 0x30, // Usage (X) 36
* 0x09, 0x31, // Usage (Y) 38
* 0x16, 0x01, 0x80, // Logical Minimum (-32767) 40
* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 43
* 0x75, 0x10, // Report Size (16) 46
* 0x95, 0x02, // Report Count (2) 48
* 0x81, 0x06, // Input (Data,Var,Rel) 50
* 0x09, 0x38, // Usage (Wheel) 52
* 0x15, 0x81, // Logical Minimum (-127) 54
* 0x25, 0x7f, // Logical Maximum (127) 56
* 0x75, 0x08, // Report Size (8) 58
* 0x95, 0x01, // Report Count (1) 60
* 0x81, 0x06, // Input (Data,Var,Rel) 62
* 0xc0, // End Collection 64
* 0xc0, // End Collection 65
* 0x05, 0x0c, // Usage Page (Consumer Devices) 66
* 0x09, 0x01, // Usage (Consumer Control) 68
* 0xa1, 0x01, // Collection (Application) 70
* 0x85, 0x02, // Report ID (2) 72
* 0x75, 0x10, // Report Size (16) 74
* 0x95, 0x01, // Report Count (1) 76
* 0x15, 0x01, // Logical Minimum (1) 78
* 0x26, 0x8c, 0x02, // Logical Maximum (652) 80
* 0x19, 0x01, // Usage Minimum (1) 83
* 0x2a, 0x8c, 0x02, // Usage Maximum (652) 85
* 0x81, 0x00, // Input (Data,Arr,Abs) 88
* 0xc0, // End Collection 90
* 0x05, 0x01, // Usage Page (Generic Desktop) 91
* 0x09, 0x80, // Usage (System Control) 93
* 0xa1, 0x01, // Collection (Application) 95
* 0x85, 0x03, // Report ID (3) 97
* 0x09, 0x82, // Usage (System Sleep) 99
* 0x09, 0x81, // Usage (System Power Down) 101
* 0x09, 0x83, // Usage (System Wake Up) 103
* 0x15, 0x00, // Logical Minimum (0) 105
* 0x25, 0x01, // Logical Maximum (1) 107
* 0x19, 0x01, // Usage Minimum (1) 109
* 0x29, 0x03, // Usage Maximum (3) 111
* 0x75, 0x01, // Report Size (1) 113
* 0x95, 0x03, // Report Count (3) 115
* 0x81, 0x02, // Input (Data,Var,Abs) 117
* 0x95, 0x05, // Report Count (5) 119
* 0x81, 0x01, // Input (Cnst,Arr,Abs) 121
* 0xc0, // End Collection 123
* 0x05, 0x01, // Usage Page (Generic Desktop) 124
* 0x09, 0x00, // Usage (Undefined) 126
* 0xa1, 0x01, // Collection (Application) 128
* 0x85, 0x05, // Report ID (5) 130
* 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 132
* 0x09, 0x01, // Usage (Vendor Usage 1) 135
* 0x15, 0x81, // Logical Minimum (-127) 137
* 0x25, 0x7f, // Logical Maximum (127) 139
* 0x75, 0x08, // Report Size (8) 141
* 0x95, 0x07, // Report Count (7) 143
* 0xb1, 0x02, // Feature (Data,Var,Abs) 145
* 0xc0, // End Collection 147
* 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 148
* 0x09, 0x0e, // Usage (Vendor Usage 0x0e) 151
* 0xa1, 0x01, // Collection (Application) 153
* 0x85, 0xba, // Report ID (186) 155
* 0x95, 0x1f, // Report Count (31) 157
* 0x75, 0x08, // Report Size (8) 159
* 0x26, 0xff, 0x00, // Logical Maximum (255) 161
* 0x15, 0x00, // Logical Minimum (0) 164
* 0x09, 0x01, // Usage (Vendor Usage 1) 166
* 0x91, 0x02, // Output (Data,Var,Abs) 168
* 0x85, 0xba, // Report ID (186) 170
* 0x95, 0x1f, // Report Count (31) 172
* 0x75, 0x08, // Report Size (8) 174
* 0x26, 0xff, 0x00, // Logical Maximum (255) 176
* 0x15, 0x00, // Logical Minimum (0) 179
* 0x09, 0x01, // Usage (Vendor Usage 1) 181
* 0x81, 0x02, // Input (Data,Var,Abs) 183
* 0xc0, // End Collection 185
*/
SEC(HID_BPF_RDESC_FIXUP)
int BPF_PROG(hid_rdesc_fixup_rapoo_m50, struct hid_bpf_ctx *hctx)
{
__u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
if (!data)
return 0; /* EPERM check */
if (data[17] == 0x03)
data[17] = 0x05;
return 0;
}
HID_BPF_OPS(rapoo_m50) = {
.hid_rdesc_fixup = (void *)hid_rdesc_fixup_rapoo_m50,
};
SEC("syscall")
int probe(struct hid_bpf_probe_args *ctx)
{
ctx->retval = ctx->rdesc_size != RDESC_SIZE;
if (ctx->retval)
ctx->retval = -EINVAL;
return 0;
}
char _license[] SEC("license") = "GPL";
+27 -9
View File
@@ -52,7 +52,8 @@
* Usage_GD_Keyboard
* CollectionApplication( Open the collection
* ReportId(3)
* LogicalRange_i8(0, 1)
* LogicalMinimum_i8(0)
* LogicalMaximum_i8(1)
* // other fields
* ) End EndCollection
*
@@ -74,26 +75,43 @@
#define Arr 0x0
#define Abs 0x0
#define Rel 0x4
#define Null 0x40
#define Buff 0x0100
/* Use like this: Input(Var|Abs) */
#define Input(i_) 0x081, i8(i_),
#define Output(i_) 0x091, i8(i_),
#define Feature(i_) 0x0b1, i8(i_),
#define Input_i16(i_) 0x082, LE16(i_),
#define Output_i16(i_) 0x092, LE16(i_),
#define Feature_i16(i_) 0x0b2, LE16(i_),
#define ReportId(id_) 0x85, i8(id_),
#define ReportSize(sz_) 0x75, i8(sz_),
#define ReportCount(cnt_) 0x95, i8(cnt_),
#define LogicalRange_i8(min_, max_) 0x15, i8(min_), 0x25, i8(max_),
#define LogicalRange_i16(min_, max_) 0x16, LE16(min_), 0x26, LE16(max_),
#define LogicalRange_i32(min_, max_) 0x17, LE32(min_), 0x27, LE32(max_),
#define LogicalMinimum_i8(min_) 0x15, i8(min_),
#define LogicalMinimum_i16(min_) 0x16, LE16(min_),
#define LogicalMinimum_i32(min_) 0x17, LE32(min_),
#define PhysicalRange_i8(min_, max_) 0x35, i8(min_), 0x45, i8(max_),
#define PhysicalRange_i16(min_, max_) 0x36, LE16(min_), 0x46, LE16(max_),
#define PhysicalRange_i32(min_, max_) 0x37, LE32(min_), 0x47, LE32(max_),
#define LogicalMaximum_i8(max_) 0x25, i8(max_),
#define LogicalMaximum_i16(max_) 0x26, LE16(max_),
#define LogicalMaximum_i32(max_) 0x27, LE32(max_),
#define UsageRange_i8(min_, max_) 0x19, i8(min_), 0x29, i8(max_),
#define UsageRange_i16(min_, max_) 0x1a, LE16(min_), 0x2a, LE16(max_),
#define PhysicalMinimum_i8(min_) 0x35, i8(min_),
#define PhysicalMinimum_i16(min_) 0x36, LE16(min_),
#define PhysicalMinimum_i32(min_) 0x37, LE32(min_),
#define PhysicalMaximum_i8(max_) 0x45, i8(max_),
#define PhysicalMaximum_i16(max_) 0x46, LE16(max_),
#define PhysicalMaximum_i32(max_) 0x47, LE32(max_),
#define UsageMinimum_i8(min_) 0x19, i8(min_),
#define UsageMinimum_i16(min_) 0x1a, LE16(min_),
#define UsageMaximum_i8(max_) 0x29, i8(max_),
#define UsageMaximum_i16(max_) 0x2a, LE16(max_),
#define UsagePage_i8(p_) 0x05, i8(p_),
#define UsagePage_i16(p_) 0x06, LE16(p_),
+65 -19
View File
@@ -713,7 +713,14 @@ static void hid_close_report(struct hid_device *device)
INIT_LIST_HEAD(&report_enum->report_list);
}
kfree(device->rdesc);
/*
* If the HID driver had a rdesc_fixup() callback, dev->rdesc
* will be allocated by hid-core and needs to be freed.
* Otherwise, it is either equal to dev_rdesc or bpf_rdesc, in
* which cases it'll be freed later on device removal or destroy.
*/
if (device->rdesc != device->dev_rdesc && device->rdesc != device->bpf_rdesc)
kfree(device->rdesc);
device->rdesc = NULL;
device->rsize = 0;
@@ -726,6 +733,14 @@ static void hid_close_report(struct hid_device *device)
device->status &= ~HID_STAT_PARSED;
}
static inline void hid_free_bpf_rdesc(struct hid_device *hdev)
{
/* bpf_rdesc is either equal to dev_rdesc or allocated by call_hid_bpf_rdesc_fixup() */
if (hdev->bpf_rdesc != hdev->dev_rdesc)
kfree(hdev->bpf_rdesc);
hdev->bpf_rdesc = NULL;
}
/*
* Free a device structure, all reports, and all fields.
*/
@@ -735,6 +750,7 @@ void hiddev_free(struct kref *ref)
struct hid_device *hid = container_of(ref, struct hid_device, ref);
hid_close_report(hid);
hid_free_bpf_rdesc(hid);
kfree(hid->dev_rdesc);
kfree(hid);
}
@@ -1227,7 +1243,6 @@ int hid_open_report(struct hid_device *device)
struct hid_item item;
unsigned int size;
const __u8 *start;
__u8 *buf;
const __u8 *end;
const __u8 *next;
int ret;
@@ -1243,25 +1258,34 @@ int hid_open_report(struct hid_device *device)
if (WARN_ON(device->status & HID_STAT_PARSED))
return -EBUSY;
start = device->dev_rdesc;
start = device->bpf_rdesc;
if (WARN_ON(!start))
return -ENODEV;
size = device->dev_rsize;
size = device->bpf_rsize;
/* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */
buf = call_hid_bpf_rdesc_fixup(device, start, &size);
if (buf == NULL)
return -ENOMEM;
if (device->driver->report_fixup) {
/*
* device->driver->report_fixup() needs to work
* on a copy of our report descriptor so it can
* change it.
*/
__u8 *buf = kmemdup(start, size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if (device->driver->report_fixup)
start = device->driver->report_fixup(device, buf, &size);
else
start = buf;
start = kmemdup(start, size, GFP_KERNEL);
kfree(buf);
if (start == NULL)
return -ENOMEM;
/*
* The second kmemdup is required in case report_fixup() returns
* a static read-only memory, but we have no idea if that memory
* needs to be cleaned up or not at the end.
*/
start = kmemdup(start, size, GFP_KERNEL);
kfree(buf);
if (start == NULL)
return -ENOMEM;
}
device->rdesc = start;
device->rsize = size;
@@ -2656,9 +2680,10 @@ static bool hid_check_device_match(struct hid_device *hdev,
/*
* hid-generic implements .match(), so we must be dealing with a
* different HID driver here, and can simply check if
* hid_ignore_special_drivers is set or not.
* hid_ignore_special_drivers or HID_QUIRK_IGNORE_SPECIAL_DRIVER
* are set or not.
*/
return !hid_ignore_special_drivers;
return !hid_ignore_special_drivers && !(hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER);
}
static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
@@ -2666,6 +2691,27 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
const struct hid_device_id *id;
int ret;
if (!hdev->bpf_rsize) {
unsigned int quirks;
/* reset the quirks that has been previously set */
quirks = hid_lookup_quirk(hdev);
hdev->quirks = quirks;
/* in case a bpf program gets detached, we need to free the old one */
hid_free_bpf_rdesc(hdev);
/* keep this around so we know we called it once */
hdev->bpf_rsize = hdev->dev_rsize;
/* call_hid_bpf_rdesc_fixup will always return a valid pointer */
hdev->bpf_rdesc = call_hid_bpf_rdesc_fixup(hdev, hdev->dev_rdesc,
&hdev->bpf_rsize);
if (quirks ^ hdev->quirks)
hid_info(hdev, "HID-BPF toggled quirks on the device: %04x",
quirks ^ hdev->quirks);
}
if (!hid_check_device_match(hdev, hdrv, &id))
return -ENODEV;
@@ -2673,8 +2719,6 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
if (!hdev->devres_group_id)
return -ENOMEM;
/* reset the quirks that has been previously set */
hdev->quirks = hid_lookup_quirk(hdev);
hdev->driver = hdrv;
if (hdrv->probe) {
@@ -2922,9 +2966,11 @@ static void hid_remove_device(struct hid_device *hdev)
hid_debug_unregister(hdev);
hdev->status &= ~HID_STAT_ADDED;
}
hid_free_bpf_rdesc(hdev);
kfree(hdev->dev_rdesc);
hdev->dev_rdesc = NULL;
hdev->dev_rsize = 0;
hdev->bpf_rsize = 0;
}
/**
+3
View File
@@ -40,6 +40,9 @@ static bool hid_generic_match(struct hid_device *hdev,
if (ignore_special_driver)
return true;
if (hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER)
return true;
if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)
return false;