mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 11:31:31 +00:00
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:
commit
903796855b
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
drivers/hid/bpf/progs/Mistel__MD770.bpf.c
Normal file
154
drivers/hid/bpf/progs/Mistel__MD770.bpf.c
Normal 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";
|
148
drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c
Normal file
148
drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c
Normal file
@ -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";
|
@ -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_),
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
|
@ -359,6 +359,7 @@ struct hid_item {
|
||||
* | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP:
|
||||
* | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
|
||||
* | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
|
||||
* | @HID_QUIRK_IGNORE_SPECIAL_DRIVER
|
||||
* | @HID_QUIRK_FULLSPEED_INTERVAL:
|
||||
* | @HID_QUIRK_NO_INIT_REPORTS:
|
||||
* | @HID_QUIRK_NO_IGNORE:
|
||||
@ -384,6 +385,7 @@ struct hid_item {
|
||||
#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19)
|
||||
#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
|
||||
#define HID_QUIRK_NOINVERT BIT(21)
|
||||
#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)
|
||||
#define HID_QUIRK_NO_INIT_REPORTS BIT(29)
|
||||
#define HID_QUIRK_NO_IGNORE BIT(30)
|
||||
@ -599,15 +601,17 @@ enum hid_battery_status {
|
||||
struct hid_driver;
|
||||
struct hid_ll_driver;
|
||||
|
||||
struct hid_device { /* device report descriptor */
|
||||
const __u8 *dev_rdesc;
|
||||
unsigned dev_rsize;
|
||||
const __u8 *rdesc;
|
||||
unsigned rsize;
|
||||
struct hid_device {
|
||||
const __u8 *dev_rdesc; /* device report descriptor */
|
||||
const __u8 *bpf_rdesc; /* bpf modified report descriptor, if any */
|
||||
const __u8 *rdesc; /* currently used report descriptor */
|
||||
unsigned int dev_rsize;
|
||||
unsigned int bpf_rsize;
|
||||
unsigned int rsize;
|
||||
unsigned int collection_size; /* Number of allocated hid_collections */
|
||||
struct hid_collection *collection; /* List of HID collections */
|
||||
unsigned collection_size; /* Number of allocated hid_collections */
|
||||
unsigned maxcollection; /* Number of parsed collections */
|
||||
unsigned maxapplication; /* Number of applications */
|
||||
unsigned int maxcollection; /* Number of parsed collections */
|
||||
unsigned int maxapplication; /* Number of applications */
|
||||
__u16 bus; /* BUS ID */
|
||||
__u16 group; /* Report group */
|
||||
__u32 vendor; /* Vendor ID */
|
||||
|
@ -212,7 +212,7 @@ int hid_bpf_connect_device(struct hid_device *hdev);
|
||||
void hid_bpf_disconnect_device(struct hid_device *hdev);
|
||||
void hid_bpf_destroy_device(struct hid_device *hid);
|
||||
int hid_bpf_device_init(struct hid_device *hid);
|
||||
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);
|
||||
#else /* CONFIG_HID_BPF */
|
||||
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
|
||||
u8 *data, u32 *size, int interrupt,
|
||||
@ -228,13 +228,8 @@ static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
|
||||
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
|
||||
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
|
||||
static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
|
||||
/*
|
||||
* This specialized allocator has to be a macro for its allocations to be
|
||||
* accounted separately (to have a separate alloc_tag). The typecast is
|
||||
* intentional to enforce typesafety.
|
||||
*/
|
||||
#define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \
|
||||
((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL))
|
||||
static inline const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc,
|
||||
unsigned int *size) { return rdesc; }
|
||||
|
||||
#endif /* CONFIG_HID_BPF */
|
||||
|
||||
|
@ -232,7 +232,7 @@ $(BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(OUTPUT)
|
||||
$(Q)$(BPFTOOL) gen object $(<:.o=.linked1.o) $<
|
||||
$(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.o=)) > $@
|
||||
|
||||
$(OUTPUT)/%.o: %.c $(BPF_SKELS)
|
||||
$(OUTPUT)/%.o: %.c $(BPF_SKELS) hid_common.h
|
||||
$(call msg,CC,,$@)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
|
||||
|
||||
|
@ -4,13 +4,6 @@
|
||||
#include "hid_common.h"
|
||||
#include <bpf/bpf.h>
|
||||
|
||||
struct attach_prog_args {
|
||||
int prog_fd;
|
||||
unsigned int hid;
|
||||
int retval;
|
||||
int insert_head;
|
||||
};
|
||||
|
||||
struct hid_hw_request_syscall_args {
|
||||
__u8 data[10];
|
||||
unsigned int hid;
|
||||
@ -21,11 +14,8 @@ struct hid_hw_request_syscall_args {
|
||||
};
|
||||
|
||||
FIXTURE(hid_bpf) {
|
||||
int dev_id;
|
||||
int uhid_fd;
|
||||
struct uhid_device hid;
|
||||
int hidraw_fd;
|
||||
int hid_id;
|
||||
pthread_t tid;
|
||||
struct hid *skel;
|
||||
struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */
|
||||
};
|
||||
@ -54,35 +44,52 @@ static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)
|
||||
FIXTURE_TEARDOWN(hid_bpf) {
|
||||
void *uhid_err;
|
||||
|
||||
uhid_destroy(_metadata, self->uhid_fd);
|
||||
uhid_destroy(_metadata, &self->hid);
|
||||
|
||||
detach_bpf(self);
|
||||
pthread_join(self->tid, &uhid_err);
|
||||
pthread_join(self->hid.tid, &uhid_err);
|
||||
}
|
||||
#define TEARDOWN_LOG(fmt, ...) do { \
|
||||
TH_LOG(fmt, ##__VA_ARGS__); \
|
||||
hid_bpf_teardown(_metadata, self, variant); \
|
||||
} while (0)
|
||||
|
||||
struct specific_device {
|
||||
const char test_name[64];
|
||||
__u16 bus;
|
||||
__u32 vid;
|
||||
__u32 pid;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(hid_bpf)
|
||||
{
|
||||
time_t t;
|
||||
const struct specific_device *match = NULL;
|
||||
int err;
|
||||
|
||||
/* initialize random number generator */
|
||||
srand((unsigned int)time(&t));
|
||||
const struct specific_device devices[] = {
|
||||
{
|
||||
.test_name = "test_hid_driver_probe",
|
||||
.bus = BUS_BLUETOOTH,
|
||||
.vid = 0x05ac, /* USB_VENDOR_ID_APPLE */
|
||||
.pid = 0x022c, /* USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI */
|
||||
}, {
|
||||
.test_name = "*",
|
||||
.bus = BUS_USB,
|
||||
.vid = 0x0001,
|
||||
.pid = 0x0a36,
|
||||
}};
|
||||
|
||||
self->dev_id = rand() % 1024;
|
||||
for (int i = 0; i < ARRAY_SIZE(devices); i++) {
|
||||
match = &devices[i];
|
||||
if (!strncmp(_metadata->name, devices[i].test_name, sizeof(devices[i].test_name)))
|
||||
break;
|
||||
}
|
||||
|
||||
self->uhid_fd = setup_uhid(_metadata, self->dev_id);
|
||||
ASSERT_OK_PTR(match);
|
||||
|
||||
/* locate the uev, self, variant);ent file of the created device */
|
||||
self->hid_id = get_hid_id(self->dev_id);
|
||||
ASSERT_GT(self->hid_id, 0)
|
||||
TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id);
|
||||
|
||||
err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd);
|
||||
ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err);
|
||||
err = setup_uhid(_metadata, &self->hid, match->bus, match->vid, match->pid,
|
||||
rdesc, sizeof(rdesc));
|
||||
ASSERT_OK(err);
|
||||
}
|
||||
|
||||
struct test_program {
|
||||
@ -129,7 +136,7 @@ static void load_programs(const struct test_program programs[],
|
||||
ops_hid_id = bpf_map__initial_value(map, NULL);
|
||||
ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data");
|
||||
|
||||
*ops_hid_id = self->hid_id;
|
||||
*ops_hid_id = self->hid.hid_id;
|
||||
}
|
||||
|
||||
/* we disable the auto-attach feature of all maps because we
|
||||
@ -157,7 +164,7 @@ static void load_programs(const struct test_program programs[],
|
||||
|
||||
hid__attach(self->skel);
|
||||
|
||||
self->hidraw_fd = open_hidraw(self->dev_id);
|
||||
self->hidraw_fd = open_hidraw(&self->hid);
|
||||
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||
}
|
||||
|
||||
@ -192,7 +199,7 @@ TEST_F(hid_bpf, raw_event)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* check that hid_first_event() was executed */
|
||||
ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1");
|
||||
@ -208,7 +215,7 @@ TEST_F(hid_bpf, raw_event)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 1;
|
||||
buf[1] = 47;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* check that hid_first_event() was executed */
|
||||
ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1");
|
||||
@ -239,7 +246,7 @@ TEST_F(hid_bpf, subprog_raw_event)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -252,7 +259,7 @@ TEST_F(hid_bpf, subprog_raw_event)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 1;
|
||||
buf[1] = 47;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -303,7 +310,7 @@ TEST_F(hid_bpf, test_attach_detach)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -326,14 +333,14 @@ TEST_F(hid_bpf, test_attach_detach)
|
||||
/* detach the program */
|
||||
detach_bpf(self);
|
||||
|
||||
self->hidraw_fd = open_hidraw(self->dev_id);
|
||||
self->hidraw_fd = open_hidraw(&self->hid);
|
||||
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||
|
||||
/* inject another event */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 1;
|
||||
buf[1] = 47;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -352,7 +359,7 @@ TEST_F(hid_bpf, test_attach_detach)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -382,7 +389,7 @@ TEST_F(hid_bpf, test_hid_change_report)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -412,7 +419,7 @@ TEST_F(hid_bpf, test_hid_user_input_report_call)
|
||||
|
||||
LOAD_BPF;
|
||||
|
||||
args.hid = self->hid_id;
|
||||
args.hid = self->hid.hid_id;
|
||||
args.data[0] = 1; /* report ID */
|
||||
args.data[1] = 2; /* report ID */
|
||||
args.data[2] = 42; /* report ID */
|
||||
@ -458,7 +465,7 @@ TEST_F(hid_bpf, test_hid_user_output_report_call)
|
||||
|
||||
LOAD_BPF;
|
||||
|
||||
args.hid = self->hid_id;
|
||||
args.hid = self->hid.hid_id;
|
||||
args.data[0] = 1; /* report ID */
|
||||
args.data[1] = 2; /* report ID */
|
||||
args.data[2] = 42; /* report ID */
|
||||
@ -506,7 +513,7 @@ TEST_F(hid_bpf, test_hid_user_raw_request_call)
|
||||
|
||||
LOAD_BPF;
|
||||
|
||||
args.hid = self->hid_id;
|
||||
args.hid = self->hid.hid_id;
|
||||
args.data[0] = 1; /* report ID */
|
||||
|
||||
prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request);
|
||||
@ -539,7 +546,7 @@ TEST_F(hid_bpf, test_hid_filter_raw_request_call)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -565,7 +572,7 @@ TEST_F(hid_bpf, test_hid_filter_raw_request_call)
|
||||
/* detach the program */
|
||||
detach_bpf(self);
|
||||
|
||||
self->hidraw_fd = open_hidraw(self->dev_id);
|
||||
self->hidraw_fd = open_hidraw(&self->hid);
|
||||
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||
|
||||
err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
|
||||
@ -641,7 +648,7 @@ TEST_F(hid_bpf, test_hid_filter_output_report_call)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -667,7 +674,7 @@ TEST_F(hid_bpf, test_hid_filter_output_report_call)
|
||||
/* detach the program */
|
||||
detach_bpf(self);
|
||||
|
||||
self->hidraw_fd = open_hidraw(self->dev_id);
|
||||
self->hidraw_fd = open_hidraw(&self->hid);
|
||||
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||
|
||||
err = write(self->hidraw_fd, buf, 3);
|
||||
@ -742,7 +749,7 @@ TEST_F(hid_bpf, test_multiply_events_wq)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -780,7 +787,7 @@ TEST_F(hid_bpf, test_multiply_events)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -816,7 +823,7 @@ TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call)
|
||||
buf[1] = 2;
|
||||
buf[2] = 42;
|
||||
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -867,7 +874,7 @@ TEST_F(hid_bpf, test_hid_attach_flags)
|
||||
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -878,6 +885,54 @@ TEST_F(hid_bpf, test_hid_attach_flags)
|
||||
ASSERT_EQ(buf[3], 3);
|
||||
}
|
||||
|
||||
static bool is_using_driver(struct __test_metadata *_metadata, struct uhid_device *hid,
|
||||
const char *driver)
|
||||
{
|
||||
char driver_line[512];
|
||||
char uevent[1024];
|
||||
char temp[512];
|
||||
int fd, nread;
|
||||
bool found = false;
|
||||
|
||||
sprintf(uevent, "/sys/bus/hid/devices/%04X:%04X:%04X.%04X/uevent",
|
||||
hid->bus, hid->vid, hid->pid, hid->hid_id);
|
||||
|
||||
fd = open(uevent, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
TH_LOG("couldn't open '%s': %d, %d", uevent, fd, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf(driver_line, "DRIVER=%s", driver);
|
||||
|
||||
nread = read(fd, temp, ARRAY_SIZE(temp));
|
||||
if (nread > 0 && (strstr(temp, driver_line)) != NULL)
|
||||
found = true;
|
||||
|
||||
close(fd);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach hid_driver_probe to the given uhid device,
|
||||
* check that the device is now using hid-generic.
|
||||
*/
|
||||
TEST_F(hid_bpf, test_hid_driver_probe)
|
||||
{
|
||||
const struct test_program progs[] = {
|
||||
{
|
||||
.name = "hid_test_driver_probe",
|
||||
},
|
||||
};
|
||||
|
||||
ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "apple"));
|
||||
|
||||
LOAD_PROGRAMS(progs);
|
||||
|
||||
ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "hid-generic"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach hid_rdesc_fixup to the given uhid device,
|
||||
* retrieve and open the matching hidraw node,
|
||||
|
@ -19,6 +19,16 @@
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
struct uhid_device {
|
||||
int dev_id; /* uniq (random) number to identify the device */
|
||||
int uhid_fd;
|
||||
int hid_id; /* HID device id in the system */
|
||||
__u16 bus;
|
||||
__u32 vid;
|
||||
__u32 pid;
|
||||
pthread_t tid; /* thread for reading uhid events */
|
||||
};
|
||||
|
||||
static unsigned char rdesc[] = {
|
||||
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
|
||||
0x09, 0x21, /* Usage (Vendor Usage 0x21) */
|
||||
@ -122,7 +132,9 @@ static int uhid_write(struct __test_metadata *_metadata, int fd, const struct uh
|
||||
}
|
||||
}
|
||||
|
||||
static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb)
|
||||
static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb,
|
||||
__u16 bus, __u32 vid, __u32 pid, __u8 *rdesc,
|
||||
size_t rdesc_size)
|
||||
{
|
||||
struct uhid_event ev;
|
||||
char buf[25];
|
||||
@ -133,10 +145,10 @@ static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb)
|
||||
ev.type = UHID_CREATE;
|
||||
strcpy((char *)ev.u.create.name, buf);
|
||||
ev.u.create.rd_data = rdesc;
|
||||
ev.u.create.rd_size = sizeof(rdesc);
|
||||
ev.u.create.bus = BUS_USB;
|
||||
ev.u.create.vendor = 0x0001;
|
||||
ev.u.create.product = 0x0a37;
|
||||
ev.u.create.rd_size = rdesc_size;
|
||||
ev.u.create.bus = bus;
|
||||
ev.u.create.vendor = vid;
|
||||
ev.u.create.product = pid;
|
||||
ev.u.create.version = 0;
|
||||
ev.u.create.country = 0;
|
||||
|
||||
@ -146,14 +158,14 @@ static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb)
|
||||
return uhid_write(_metadata, fd, &ev);
|
||||
}
|
||||
|
||||
static void uhid_destroy(struct __test_metadata *_metadata, int fd)
|
||||
static void uhid_destroy(struct __test_metadata *_metadata, struct uhid_device *hid)
|
||||
{
|
||||
struct uhid_event ev;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = UHID_DESTROY;
|
||||
|
||||
uhid_write(_metadata, fd, &ev);
|
||||
uhid_write(_metadata, hid->uhid_fd, &ev);
|
||||
}
|
||||
|
||||
static int uhid_event(struct __test_metadata *_metadata, int fd)
|
||||
@ -281,7 +293,8 @@ static int uhid_start_listener(struct __test_metadata *_metadata, pthread_t *tid
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uhid_send_event(struct __test_metadata *_metadata, int fd, __u8 *buf, size_t size)
|
||||
static int uhid_send_event(struct __test_metadata *_metadata, struct uhid_device *hid,
|
||||
__u8 *buf, size_t size)
|
||||
{
|
||||
struct uhid_event ev;
|
||||
|
||||
@ -294,36 +307,20 @@ static int uhid_send_event(struct __test_metadata *_metadata, int fd, __u8 *buf,
|
||||
|
||||
memcpy(ev.u.input2.data, buf, size);
|
||||
|
||||
return uhid_write(_metadata, fd, &ev);
|
||||
return uhid_write(_metadata, hid->uhid_fd, &ev);
|
||||
}
|
||||
|
||||
static int setup_uhid(struct __test_metadata *_metadata, int rand_nb)
|
||||
static bool match_sysfs_device(struct uhid_device *hid, const char *workdir, struct dirent *dir)
|
||||
{
|
||||
int fd;
|
||||
const char *path = "/dev/uhid";
|
||||
int ret;
|
||||
|
||||
fd = open(path, O_RDWR | O_CLOEXEC);
|
||||
ASSERT_GE(fd, 0) TH_LOG("open uhid-cdev failed; %d", fd);
|
||||
|
||||
ret = uhid_create(_metadata, fd, rand_nb);
|
||||
ASSERT_EQ(0, ret) {
|
||||
TH_LOG("create uhid device failed: %d", ret);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static bool match_sysfs_device(int dev_id, const char *workdir, struct dirent *dir)
|
||||
{
|
||||
const char *target = "0003:0001:0A37.*";
|
||||
char target[20] = "";
|
||||
char phys[512];
|
||||
char uevent[1024];
|
||||
char temp[512];
|
||||
int fd, nread;
|
||||
bool found = false;
|
||||
|
||||
snprintf(target, sizeof(target), "%04X:%04X:%04X.*", hid->bus, hid->vid, hid->pid);
|
||||
|
||||
if (fnmatch(target, dir->d_name, 0))
|
||||
return false;
|
||||
|
||||
@ -334,7 +331,7 @@ static bool match_sysfs_device(int dev_id, const char *workdir, struct dirent *d
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
sprintf(phys, "PHYS=%d", dev_id);
|
||||
sprintf(phys, "PHYS=%d", hid->dev_id);
|
||||
|
||||
nread = read(fd, temp, ARRAY_SIZE(temp));
|
||||
if (nread > 0 && (strstr(temp, phys)) != NULL)
|
||||
@ -345,7 +342,7 @@ static bool match_sysfs_device(int dev_id, const char *workdir, struct dirent *d
|
||||
return found;
|
||||
}
|
||||
|
||||
static int get_hid_id(int dev_id)
|
||||
static int get_hid_id(struct uhid_device *hid)
|
||||
{
|
||||
const char *workdir = "/sys/devices/virtual/misc/uhid";
|
||||
const char *str_id;
|
||||
@ -360,10 +357,10 @@ static int get_hid_id(int dev_id)
|
||||
d = opendir(workdir);
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (!match_sysfs_device(dev_id, workdir, dir))
|
||||
if (!match_sysfs_device(hid, workdir, dir))
|
||||
continue;
|
||||
|
||||
str_id = dir->d_name + sizeof("0003:0001:0A37.");
|
||||
str_id = dir->d_name + sizeof("0000:0000:0000.");
|
||||
found = (int)strtol(str_id, NULL, 16);
|
||||
|
||||
break;
|
||||
@ -377,7 +374,7 @@ static int get_hid_id(int dev_id)
|
||||
return found;
|
||||
}
|
||||
|
||||
static int get_hidraw(int dev_id)
|
||||
static int get_hidraw(struct uhid_device *hid)
|
||||
{
|
||||
const char *workdir = "/sys/devices/virtual/misc/uhid";
|
||||
char sysfs[1024];
|
||||
@ -394,7 +391,7 @@ static int get_hidraw(int dev_id)
|
||||
continue;
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (!match_sysfs_device(dev_id, workdir, dir))
|
||||
if (!match_sysfs_device(hid, workdir, dir))
|
||||
continue;
|
||||
|
||||
sprintf(sysfs, "%s/%s/hidraw", workdir, dir->d_name);
|
||||
@ -421,12 +418,12 @@ static int get_hidraw(int dev_id)
|
||||
return found;
|
||||
}
|
||||
|
||||
static int open_hidraw(int dev_id)
|
||||
static int open_hidraw(struct uhid_device *hid)
|
||||
{
|
||||
int hidraw_number;
|
||||
char hidraw_path[64] = { 0 };
|
||||
|
||||
hidraw_number = get_hidraw(dev_id);
|
||||
hidraw_number = get_hidraw(hid);
|
||||
if (hidraw_number < 0)
|
||||
return hidraw_number;
|
||||
|
||||
@ -434,3 +431,44 @@ static int open_hidraw(int dev_id)
|
||||
sprintf(hidraw_path, "/dev/hidraw%d", hidraw_number);
|
||||
return open(hidraw_path, O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
|
||||
static int setup_uhid(struct __test_metadata *_metadata, struct uhid_device *hid,
|
||||
__u16 bus, __u32 vid, __u32 pid, const __u8 *rdesc, size_t rdesc_size)
|
||||
{
|
||||
const char *path = "/dev/uhid";
|
||||
time_t t;
|
||||
int ret;
|
||||
|
||||
/* initialize random number generator */
|
||||
srand((unsigned int)time(&t));
|
||||
|
||||
hid->dev_id = rand() % 1024;
|
||||
hid->bus = bus;
|
||||
hid->vid = vid;
|
||||
hid->pid = pid;
|
||||
|
||||
hid->uhid_fd = open(path, O_RDWR | O_CLOEXEC);
|
||||
ASSERT_GE(hid->uhid_fd, 0) TH_LOG("open uhid-cdev failed; %d", hid->uhid_fd);
|
||||
|
||||
ret = uhid_create(_metadata, hid->uhid_fd, hid->dev_id, bus, vid, pid,
|
||||
(__u8 *)rdesc, rdesc_size);
|
||||
ASSERT_EQ(0, ret) {
|
||||
TH_LOG("create uhid device failed: %d", ret);
|
||||
close(hid->uhid_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* locate the uevent file of the created device */
|
||||
hid->hid_id = get_hid_id(hid);
|
||||
ASSERT_GT(hid->hid_id, 0)
|
||||
TH_LOG("Could not locate uhid device id: %d", hid->hid_id);
|
||||
|
||||
ret = uhid_start_listener(_metadata, &hid->tid, hid->uhid_fd);
|
||||
ASSERT_EQ(0, ret) {
|
||||
TH_LOG("could not start udev listener: %d", ret);
|
||||
close(hid->uhid_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,11 +9,8 @@
|
||||
#endif /* HIDIOCREVOKE */
|
||||
|
||||
FIXTURE(hidraw) {
|
||||
int dev_id;
|
||||
int uhid_fd;
|
||||
struct uhid_device hid;
|
||||
int hidraw_fd;
|
||||
int hid_id;
|
||||
pthread_t tid;
|
||||
};
|
||||
static void close_hidraw(FIXTURE_DATA(hidraw) * self)
|
||||
{
|
||||
@ -25,10 +22,10 @@ static void close_hidraw(FIXTURE_DATA(hidraw) * self)
|
||||
FIXTURE_TEARDOWN(hidraw) {
|
||||
void *uhid_err;
|
||||
|
||||
uhid_destroy(_metadata, self->uhid_fd);
|
||||
uhid_destroy(_metadata, &self->hid);
|
||||
|
||||
close_hidraw(self);
|
||||
pthread_join(self->tid, &uhid_err);
|
||||
pthread_join(self->hid.tid, &uhid_err);
|
||||
}
|
||||
#define TEARDOWN_LOG(fmt, ...) do { \
|
||||
TH_LOG(fmt, ##__VA_ARGS__); \
|
||||
@ -37,25 +34,12 @@ FIXTURE_TEARDOWN(hidraw) {
|
||||
|
||||
FIXTURE_SETUP(hidraw)
|
||||
{
|
||||
time_t t;
|
||||
int err;
|
||||
|
||||
/* initialize random number generator */
|
||||
srand((unsigned int)time(&t));
|
||||
err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc));
|
||||
ASSERT_OK(err);
|
||||
|
||||
self->dev_id = rand() % 1024;
|
||||
|
||||
self->uhid_fd = setup_uhid(_metadata, self->dev_id);
|
||||
|
||||
/* locate the uev, self, variant);ent file of the created device */
|
||||
self->hid_id = get_hid_id(self->dev_id);
|
||||
ASSERT_GT(self->hid_id, 0)
|
||||
TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id);
|
||||
|
||||
err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd);
|
||||
ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err);
|
||||
|
||||
self->hidraw_fd = open_hidraw(self->dev_id);
|
||||
self->hidraw_fd = open_hidraw(&self->hid);
|
||||
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||
}
|
||||
|
||||
@ -79,7 +63,7 @@ TEST_F(hidraw, raw_event)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -101,7 +85,7 @@ TEST_F(hidraw, raw_event_revoked)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -117,7 +101,7 @@ TEST_F(hidraw, raw_event_revoked)
|
||||
/* inject one other event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 43;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
/* read the data from hidraw */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@ -161,7 +145,7 @@ TEST_F(hidraw, poll_revoked)
|
||||
/* inject one event */
|
||||
buf[0] = 1;
|
||||
buf[1] = 42;
|
||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
||||
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||
|
||||
while (true) {
|
||||
ready = poll(pfds, 1, 5000);
|
||||
|
@ -598,3 +598,15 @@ SEC(".struct_ops.link")
|
||||
struct hid_bpf_ops test_infinite_loop_input_report = {
|
||||
.hid_device_event = (void *)hid_test_infinite_loop_input_report,
|
||||
};
|
||||
|
||||
SEC("?struct_ops.s/hid_rdesc_fixup")
|
||||
int BPF_PROG(hid_test_driver_probe, struct hid_bpf_ctx *hid_ctx)
|
||||
{
|
||||
hid_ctx->hid->quirks |= HID_QUIRK_IGNORE_SPECIAL_DRIVER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC(".struct_ops.link")
|
||||
struct hid_bpf_ops test_driver_probe = {
|
||||
.hid_rdesc_fixup = (void *)hid_test_driver_probe,
|
||||
};
|
||||
|
@ -84,10 +84,14 @@ struct hid_bpf_ops {
|
||||
struct hid_device *hdev;
|
||||
};
|
||||
|
||||
#define BIT(n) (1U << n)
|
||||
|
||||
#ifndef BPF_F_BEFORE
|
||||
#define BPF_F_BEFORE (1U << 3)
|
||||
#define BPF_F_BEFORE BIT(3)
|
||||
#endif
|
||||
|
||||
#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)
|
||||
|
||||
/* following are kfuncs exported by HID for HID-BPF */
|
||||
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
|
||||
unsigned int offset,
|
||||
|
Loading…
Reference in New Issue
Block a user