mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +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);
|
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;
|
int ret;
|
||||||
struct hid_bpf_ctx_kern ctx_kern = {
|
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:
|
ignore_bpf:
|
||||||
kfree(ctx_kern.data);
|
kfree(ctx_kern.data);
|
||||||
return kmemdup(rdesc, *size, GFP_KERNEL);
|
return rdesc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
|
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)
|
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 device_reprobe(&hdev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
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, name, true),
|
||||||
WRITE_RANGE(hid_device, uniq, true),
|
WRITE_RANGE(hid_device, uniq, true),
|
||||||
WRITE_RANGE(hid_device, phys, true),
|
WRITE_RANGE(hid_device, phys, true),
|
||||||
|
WRITE_RANGE(hid_device, quirks, false),
|
||||||
};
|
};
|
||||||
#undef WRITE_RANGE
|
#undef WRITE_RANGE
|
||||||
const struct btf_type *state = NULL;
|
const struct btf_type *state = NULL;
|
||||||
|
@ -214,7 +214,8 @@ static const __u8 fixed_rdesc_pad[] = {
|
|||||||
CollectionApplication(
|
CollectionApplication(
|
||||||
// -- Byte 0 in report
|
// -- Byte 0 in report
|
||||||
ReportId(PAD_REPORT_ID)
|
ReportId(PAD_REPORT_ID)
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMaximum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
UsagePage_Digitizers
|
UsagePage_Digitizers
|
||||||
Usage_Dig_TabletFunctionKeys
|
Usage_Dig_TabletFunctionKeys
|
||||||
CollectionPhysical(
|
CollectionPhysical(
|
||||||
@ -234,14 +235,17 @@ static const __u8 fixed_rdesc_pad[] = {
|
|||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
// Byte 4 in report is the dial
|
// Byte 4 in report is the dial
|
||||||
Usage_GD_Wheel
|
Usage_GD_Wheel
|
||||||
LogicalRange_i8(-1, 1)
|
LogicalMinimum_i8(-1)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportCount(1)
|
ReportCount(1)
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
Input(Var|Rel)
|
Input(Var|Rel)
|
||||||
// Byte 5 is the button state
|
// Byte 5 is the button state
|
||||||
UsagePage_Button
|
UsagePage_Button
|
||||||
UsageRange_i8(0x01, 0x8)
|
UsageMinimum_i8(0x01)
|
||||||
LogicalRange_i8(0x0, 0x1)
|
UsageMaximum_i8(0x08)
|
||||||
|
LogicalMinimum_i8(0x0)
|
||||||
|
LogicalMaximum_i8(0x1)
|
||||||
ReportCount(7)
|
ReportCount(7)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
@ -265,7 +269,8 @@ static const __u8 fixed_rdesc_pen[] = {
|
|||||||
Usage_Dig_TipSwitch
|
Usage_Dig_TipSwitch
|
||||||
Usage_Dig_BarrelSwitch
|
Usage_Dig_BarrelSwitch
|
||||||
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
|
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
ReportCount(3)
|
ReportCount(3)
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
@ -280,22 +285,28 @@ static const __u8 fixed_rdesc_pen[] = {
|
|||||||
UsagePage_GenericDesktop
|
UsagePage_GenericDesktop
|
||||||
Unit(cm)
|
Unit(cm)
|
||||||
UnitExponent(-1)
|
UnitExponent(-1)
|
||||||
PhysicalRange_i16(0, 266)
|
PhysicalMinimum_i16(0)
|
||||||
LogicalRange_i16(0, 32767)
|
PhysicalMaximum_i16(266)
|
||||||
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(32767)
|
||||||
Usage_GD_X
|
Usage_GD_X
|
||||||
Input(Var|Abs) // Bytes 2+3
|
Input(Var|Abs) // Bytes 2+3
|
||||||
PhysicalRange_i16(0, 166)
|
PhysicalMinimum_i16(0)
|
||||||
LogicalRange_i16(0, 32767)
|
PhysicalMaximum_i16(166)
|
||||||
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(32767)
|
||||||
Usage_GD_Y
|
Usage_GD_Y
|
||||||
Input(Var|Abs) // Bytes 4+5
|
Input(Var|Abs) // Bytes 4+5
|
||||||
)
|
)
|
||||||
UsagePage_Digitizers
|
UsagePage_Digitizers
|
||||||
Usage_Dig_TipPressure
|
Usage_Dig_TipPressure
|
||||||
LogicalRange_i16(0, 8191)
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(8191)
|
||||||
Input(Var|Abs) // Byte 6+7
|
Input(Var|Abs) // Byte 6+7
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
ReportCount(2)
|
ReportCount(2)
|
||||||
LogicalRange_i8(-60, 60)
|
LogicalMinimum_i8(-60)
|
||||||
|
LogicalMaximum_i8(60)
|
||||||
Usage_Dig_XTilt
|
Usage_Dig_XTilt
|
||||||
Usage_Dig_YTilt
|
Usage_Dig_YTilt
|
||||||
Input(Var|Abs) // Byte 8+9
|
Input(Var|Abs) // Byte 8+9
|
||||||
@ -313,7 +324,8 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
Usage_Dig_Pen
|
Usage_Dig_Pen
|
||||||
CollectionPhysical(
|
CollectionPhysical(
|
||||||
// Byte 1 are the buttons
|
// Byte 1 are the buttons
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
Usage_Dig_TipSwitch
|
Usage_Dig_TipSwitch
|
||||||
Usage_Dig_BarrelSwitch
|
Usage_Dig_BarrelSwitch
|
||||||
@ -333,25 +345,31 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
UnitExponent(-1)
|
UnitExponent(-1)
|
||||||
// Note: reported logical range differs
|
// Note: reported logical range differs
|
||||||
// from the pen report ID for x and y
|
// from the pen report ID for x and y
|
||||||
LogicalRange_i16(0, 53340)
|
LogicalMinimum_i16(0)
|
||||||
PhysicalRange_i16(0, 266)
|
LogicalMaximum_i16(53340)
|
||||||
|
PhysicalMinimum_i16(0)
|
||||||
|
PhysicalMaximum_i16(266)
|
||||||
// Bytes 2/3 in report
|
// Bytes 2/3 in report
|
||||||
Usage_GD_X
|
Usage_GD_X
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
LogicalRange_i16(0, 33340)
|
LogicalMinimum_i16(0)
|
||||||
PhysicalRange_i16(0, 166)
|
LogicalMaximum_i16(33340)
|
||||||
|
PhysicalMinimum_i16(0)
|
||||||
|
PhysicalMaximum_i16(166)
|
||||||
// Bytes 4/5 in report
|
// Bytes 4/5 in report
|
||||||
Usage_GD_Y
|
Usage_GD_Y
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
)
|
)
|
||||||
// Bytes 6/7 in report
|
// Bytes 6/7 in report
|
||||||
LogicalRange_i16(0, 8191)
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(8191)
|
||||||
Usage_Dig_TipPressure
|
Usage_Dig_TipPressure
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
// Bytes 8/9 in report
|
// Bytes 8/9 in report
|
||||||
ReportCount(1) // Padding
|
ReportCount(1) // Padding
|
||||||
Input(Const)
|
Input(Const)
|
||||||
LogicalRange_i8(-60, 60)
|
LogicalMinimum_i8(-60)
|
||||||
|
LogicalMaximum_i8(60)
|
||||||
// Byte 10 in report
|
// Byte 10 in report
|
||||||
Usage_Dig_XTilt
|
Usage_Dig_XTilt
|
||||||
// Byte 11 in report
|
// Byte 11 in report
|
||||||
@ -366,7 +384,8 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
CollectionApplication(
|
CollectionApplication(
|
||||||
// Byte 0
|
// Byte 0
|
||||||
ReportId(PAD_REPORT_ID)
|
ReportId(PAD_REPORT_ID)
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
UsagePage_Digitizers
|
UsagePage_Digitizers
|
||||||
Usage_Dig_TabletFunctionKeys
|
Usage_Dig_TabletFunctionKeys
|
||||||
CollectionPhysical(
|
CollectionPhysical(
|
||||||
@ -386,15 +405,18 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
// Byte 4 is the button state
|
// Byte 4 is the button state
|
||||||
UsagePage_Button
|
UsagePage_Button
|
||||||
UsageRange_i8(0x01, 0x8)
|
UsageMinimum_i8(0x1)
|
||||||
LogicalRange_i8(0x0, 0x1)
|
UsageMaximum_i8(0x8)
|
||||||
|
LogicalMinimum_i8(0x0)
|
||||||
|
LogicalMaximum_i8(0x1)
|
||||||
ReportCount(8)
|
ReportCount(8)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
// Byte 5 is the top dial
|
// Byte 5 is the top dial
|
||||||
UsagePage_GenericDesktop
|
UsagePage_GenericDesktop
|
||||||
Usage_GD_Wheel
|
Usage_GD_Wheel
|
||||||
LogicalRange_i8(-1, 1)
|
LogicalMinimum_i8(-1)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportCount(1)
|
ReportCount(1)
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
Input(Var|Rel)
|
Input(Var|Rel)
|
||||||
|
@ -170,7 +170,8 @@ static const __u8 fixed_rdesc_pad[] = {
|
|||||||
CollectionApplication(
|
CollectionApplication(
|
||||||
// -- Byte 0 in report
|
// -- Byte 0 in report
|
||||||
ReportId(PAD_REPORT_ID)
|
ReportId(PAD_REPORT_ID)
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
UsagePage_Digitizers
|
UsagePage_Digitizers
|
||||||
Usage_Dig_TabletFunctionKeys
|
Usage_Dig_TabletFunctionKeys
|
||||||
CollectionPhysical(
|
CollectionPhysical(
|
||||||
@ -190,14 +191,17 @@ static const __u8 fixed_rdesc_pad[] = {
|
|||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
// Byte 4 in report is the wheel
|
// Byte 4 in report is the wheel
|
||||||
Usage_GD_Wheel
|
Usage_GD_Wheel
|
||||||
LogicalRange_i8(-1, 1)
|
LogicalMinimum_i8(-1)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportCount(1)
|
ReportCount(1)
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
Input(Var|Rel)
|
Input(Var|Rel)
|
||||||
// Byte 5 is the button state
|
// Byte 5 is the button state
|
||||||
UsagePage_Button
|
UsagePage_Button
|
||||||
UsageRange_i8(0x01, 0x6)
|
UsageMinimum_i8(0x1)
|
||||||
LogicalRange_i8(0x01, 0x6)
|
UsageMaximum_i8(0x6)
|
||||||
|
LogicalMinimum_i8(0x1)
|
||||||
|
LogicalMaximum_i8(0x6)
|
||||||
ReportCount(1)
|
ReportCount(1)
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
Input(Arr|Abs)
|
Input(Arr|Abs)
|
||||||
@ -219,7 +223,8 @@ static const __u8 fixed_rdesc_pen[] = {
|
|||||||
Usage_Dig_TipSwitch
|
Usage_Dig_TipSwitch
|
||||||
Usage_Dig_BarrelSwitch
|
Usage_Dig_BarrelSwitch
|
||||||
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
|
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
ReportCount(3)
|
ReportCount(3)
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
@ -234,18 +239,23 @@ static const __u8 fixed_rdesc_pen[] = {
|
|||||||
UsagePage_GenericDesktop
|
UsagePage_GenericDesktop
|
||||||
Unit(cm)
|
Unit(cm)
|
||||||
UnitExponent(-1)
|
UnitExponent(-1)
|
||||||
PhysicalRange_i16(0, 160)
|
PhysicalMinimum_i16(0)
|
||||||
LogicalRange_i16(0, 32767)
|
PhysicalMaximum_i16(160)
|
||||||
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(32767)
|
||||||
Usage_GD_X
|
Usage_GD_X
|
||||||
Input(Var|Abs) // Bytes 2+3
|
Input(Var|Abs) // Bytes 2+3
|
||||||
PhysicalRange_i16(0, 100)
|
PhysicalMinimum_i16(0)
|
||||||
LogicalRange_i16(0, 32767)
|
PhysicalMaximum_i16(100)
|
||||||
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(32767)
|
||||||
Usage_GD_Y
|
Usage_GD_Y
|
||||||
Input(Var|Abs) // Bytes 4+5
|
Input(Var|Abs) // Bytes 4+5
|
||||||
)
|
)
|
||||||
UsagePage_Digitizers
|
UsagePage_Digitizers
|
||||||
Usage_Dig_TipPressure
|
Usage_Dig_TipPressure
|
||||||
LogicalRange_i16(0, 8191)
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(8191)
|
||||||
Input(Var|Abs) // Byte 6+7
|
Input(Var|Abs) // Byte 6+7
|
||||||
// Two bytes padding so we don't need to change the report at all
|
// Two bytes padding so we don't need to change the report at all
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
@ -265,7 +275,8 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
Usage_Dig_Pen
|
Usage_Dig_Pen
|
||||||
CollectionPhysical(
|
CollectionPhysical(
|
||||||
// Byte 1 are the buttons
|
// Byte 1 are the buttons
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
Usage_Dig_TipSwitch
|
Usage_Dig_TipSwitch
|
||||||
Usage_Dig_BarrelSwitch
|
Usage_Dig_BarrelSwitch
|
||||||
@ -285,19 +296,24 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
UnitExponent(-1)
|
UnitExponent(-1)
|
||||||
// Note: reported logical range differs
|
// Note: reported logical range differs
|
||||||
// from the pen report ID for x and y
|
// from the pen report ID for x and y
|
||||||
LogicalRange_i16(0, 32000)
|
LogicalMinimum_i16(0)
|
||||||
PhysicalRange_i16(0, 160)
|
LogicalMaximum_i16(32000)
|
||||||
|
PhysicalMinimum_i16(0)
|
||||||
|
PhysicalMaximum_i16(160)
|
||||||
// Bytes 2/3 in report
|
// Bytes 2/3 in report
|
||||||
Usage_GD_X
|
Usage_GD_X
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
LogicalRange_i16(0, 20000)
|
LogicalMinimum_i16(0)
|
||||||
PhysicalRange_i16(0, 100)
|
LogicalMaximum_i16(20000)
|
||||||
|
PhysicalMinimum_i16(0)
|
||||||
|
PhysicalMaximum_i16(100)
|
||||||
// Bytes 4/5 in report
|
// Bytes 4/5 in report
|
||||||
Usage_GD_Y
|
Usage_GD_Y
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
)
|
)
|
||||||
// Bytes 6/7 in report
|
// Bytes 6/7 in report
|
||||||
LogicalRange_i16(0, 8192)
|
LogicalMinimum_i16(0)
|
||||||
|
LogicalMaximum_i16(8192)
|
||||||
Usage_Dig_TipPressure
|
Usage_Dig_TipPressure
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
)
|
)
|
||||||
@ -307,7 +323,8 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
CollectionApplication(
|
CollectionApplication(
|
||||||
// Byte 0
|
// Byte 0
|
||||||
ReportId(PAD_REPORT_ID)
|
ReportId(PAD_REPORT_ID)
|
||||||
LogicalRange_i8(0, 1)
|
LogicalMinimum_i8(0)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
UsagePage_Digitizers
|
UsagePage_Digitizers
|
||||||
Usage_Dig_TabletFunctionKeys
|
Usage_Dig_TabletFunctionKeys
|
||||||
CollectionPhysical(
|
CollectionPhysical(
|
||||||
@ -327,8 +344,10 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
// Byte 4 is the button state
|
// Byte 4 is the button state
|
||||||
UsagePage_Button
|
UsagePage_Button
|
||||||
UsageRange_i8(0x01, 0x6)
|
UsageMinimum_i8(0x1)
|
||||||
LogicalRange_i8(0x0, 0x1)
|
UsageMaximum_i8(0x6)
|
||||||
|
LogicalMinimum_i8(0x0)
|
||||||
|
LogicalMaximum_i8(0x1)
|
||||||
ReportCount(6)
|
ReportCount(6)
|
||||||
ReportSize(1)
|
ReportSize(1)
|
||||||
Input(Var|Abs)
|
Input(Var|Abs)
|
||||||
@ -337,7 +356,8 @@ static const __u8 fixed_rdesc_vendor[] = {
|
|||||||
// Byte 5 is the wheel
|
// Byte 5 is the wheel
|
||||||
UsagePage_GenericDesktop
|
UsagePage_GenericDesktop
|
||||||
Usage_GD_Wheel
|
Usage_GD_Wheel
|
||||||
LogicalRange_i8(-1, 1)
|
LogicalMinimum_i8(-1)
|
||||||
|
LogicalMaximum_i8(1)
|
||||||
ReportCount(1)
|
ReportCount(1)
|
||||||
ReportSize(8)
|
ReportSize(8)
|
||||||
Input(Var|Rel)
|
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
|
* Usage_GD_Keyboard
|
||||||
* CollectionApplication( ← Open the collection
|
* CollectionApplication( ← Open the collection
|
||||||
* ReportId(3)
|
* ReportId(3)
|
||||||
* LogicalRange_i8(0, 1)
|
* LogicalMinimum_i8(0)
|
||||||
|
* LogicalMaximum_i8(1)
|
||||||
* // other fields
|
* // other fields
|
||||||
* ) ← End EndCollection
|
* ) ← End EndCollection
|
||||||
*
|
*
|
||||||
@ -74,26 +75,43 @@
|
|||||||
#define Arr 0x0
|
#define Arr 0x0
|
||||||
#define Abs 0x0
|
#define Abs 0x0
|
||||||
#define Rel 0x4
|
#define Rel 0x4
|
||||||
|
#define Null 0x40
|
||||||
|
#define Buff 0x0100
|
||||||
|
|
||||||
/* Use like this: Input(Var|Abs) */
|
/* Use like this: Input(Var|Abs) */
|
||||||
#define Input(i_) 0x081, i8(i_),
|
#define Input(i_) 0x081, i8(i_),
|
||||||
#define Output(i_) 0x091, i8(i_),
|
#define Output(i_) 0x091, i8(i_),
|
||||||
#define Feature(i_) 0x0b1, 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 ReportId(id_) 0x85, i8(id_),
|
||||||
#define ReportSize(sz_) 0x75, i8(sz_),
|
#define ReportSize(sz_) 0x75, i8(sz_),
|
||||||
#define ReportCount(cnt_) 0x95, i8(cnt_),
|
#define ReportCount(cnt_) 0x95, i8(cnt_),
|
||||||
|
|
||||||
#define LogicalRange_i8(min_, max_) 0x15, i8(min_), 0x25, i8(max_),
|
#define LogicalMinimum_i8(min_) 0x15, i8(min_),
|
||||||
#define LogicalRange_i16(min_, max_) 0x16, LE16(min_), 0x26, LE16(max_),
|
#define LogicalMinimum_i16(min_) 0x16, LE16(min_),
|
||||||
#define LogicalRange_i32(min_, max_) 0x17, LE32(min_), 0x27, LE32(max_),
|
#define LogicalMinimum_i32(min_) 0x17, LE32(min_),
|
||||||
|
|
||||||
#define PhysicalRange_i8(min_, max_) 0x35, i8(min_), 0x45, i8(max_),
|
#define LogicalMaximum_i8(max_) 0x25, i8(max_),
|
||||||
#define PhysicalRange_i16(min_, max_) 0x36, LE16(min_), 0x46, LE16(max_),
|
#define LogicalMaximum_i16(max_) 0x26, LE16(max_),
|
||||||
#define PhysicalRange_i32(min_, max_) 0x37, LE32(min_), 0x47, LE32(max_),
|
#define LogicalMaximum_i32(max_) 0x27, LE32(max_),
|
||||||
|
|
||||||
#define UsageRange_i8(min_, max_) 0x19, i8(min_), 0x29, i8(max_),
|
#define PhysicalMinimum_i8(min_) 0x35, i8(min_),
|
||||||
#define UsageRange_i16(min_, max_) 0x1a, LE16(min_), 0x2a, LE16(max_),
|
#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_i8(p_) 0x05, i8(p_),
|
||||||
#define UsagePage_i16(p_) 0x06, LE16(p_),
|
#define UsagePage_i16(p_) 0x06, LE16(p_),
|
||||||
|
@ -713,6 +713,13 @@ static void hid_close_report(struct hid_device *device)
|
|||||||
INIT_LIST_HEAD(&report_enum->report_list);
|
INIT_LIST_HEAD(&report_enum->report_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
kfree(device->rdesc);
|
||||||
device->rdesc = NULL;
|
device->rdesc = NULL;
|
||||||
device->rsize = 0;
|
device->rsize = 0;
|
||||||
@ -726,6 +733,14 @@ static void hid_close_report(struct hid_device *device)
|
|||||||
device->status &= ~HID_STAT_PARSED;
|
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.
|
* 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);
|
struct hid_device *hid = container_of(ref, struct hid_device, ref);
|
||||||
|
|
||||||
hid_close_report(hid);
|
hid_close_report(hid);
|
||||||
|
hid_free_bpf_rdesc(hid);
|
||||||
kfree(hid->dev_rdesc);
|
kfree(hid->dev_rdesc);
|
||||||
kfree(hid);
|
kfree(hid);
|
||||||
}
|
}
|
||||||
@ -1227,7 +1243,6 @@ int hid_open_report(struct hid_device *device)
|
|||||||
struct hid_item item;
|
struct hid_item item;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
const __u8 *start;
|
const __u8 *start;
|
||||||
__u8 *buf;
|
|
||||||
const __u8 *end;
|
const __u8 *end;
|
||||||
const __u8 *next;
|
const __u8 *next;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1243,25 +1258,34 @@ int hid_open_report(struct hid_device *device)
|
|||||||
if (WARN_ON(device->status & HID_STAT_PARSED))
|
if (WARN_ON(device->status & HID_STAT_PARSED))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
start = device->dev_rdesc;
|
start = device->bpf_rdesc;
|
||||||
if (WARN_ON(!start))
|
if (WARN_ON(!start))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
size = device->dev_rsize;
|
size = device->bpf_rsize;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/* 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)
|
if (buf == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (device->driver->report_fixup)
|
|
||||||
start = device->driver->report_fixup(device, buf, &size);
|
start = device->driver->report_fixup(device, buf, &size);
|
||||||
else
|
|
||||||
start = buf;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
start = kmemdup(start, size, GFP_KERNEL);
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
if (start == NULL)
|
if (start == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
device->rdesc = start;
|
device->rdesc = start;
|
||||||
device->rsize = size;
|
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
|
* hid-generic implements .match(), so we must be dealing with a
|
||||||
* different HID driver here, and can simply check if
|
* 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)
|
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;
|
const struct hid_device_id *id;
|
||||||
int ret;
|
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))
|
if (!hid_check_device_match(hdev, hdrv, &id))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
@ -2673,8 +2719,6 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
|
|||||||
if (!hdev->devres_group_id)
|
if (!hdev->devres_group_id)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* reset the quirks that has been previously set */
|
|
||||||
hdev->quirks = hid_lookup_quirk(hdev);
|
|
||||||
hdev->driver = hdrv;
|
hdev->driver = hdrv;
|
||||||
|
|
||||||
if (hdrv->probe) {
|
if (hdrv->probe) {
|
||||||
@ -2922,9 +2966,11 @@ static void hid_remove_device(struct hid_device *hdev)
|
|||||||
hid_debug_unregister(hdev);
|
hid_debug_unregister(hdev);
|
||||||
hdev->status &= ~HID_STAT_ADDED;
|
hdev->status &= ~HID_STAT_ADDED;
|
||||||
}
|
}
|
||||||
|
hid_free_bpf_rdesc(hdev);
|
||||||
kfree(hdev->dev_rdesc);
|
kfree(hdev->dev_rdesc);
|
||||||
hdev->dev_rdesc = NULL;
|
hdev->dev_rdesc = NULL;
|
||||||
hdev->dev_rsize = 0;
|
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)
|
if (ignore_special_driver)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)
|
if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -359,6 +359,7 @@ struct hid_item {
|
|||||||
* | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP:
|
* | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP:
|
||||||
* | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
|
* | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
|
||||||
* | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
|
* | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
|
||||||
|
* | @HID_QUIRK_IGNORE_SPECIAL_DRIVER
|
||||||
* | @HID_QUIRK_FULLSPEED_INTERVAL:
|
* | @HID_QUIRK_FULLSPEED_INTERVAL:
|
||||||
* | @HID_QUIRK_NO_INIT_REPORTS:
|
* | @HID_QUIRK_NO_INIT_REPORTS:
|
||||||
* | @HID_QUIRK_NO_IGNORE:
|
* | @HID_QUIRK_NO_IGNORE:
|
||||||
@ -384,6 +385,7 @@ struct hid_item {
|
|||||||
#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19)
|
#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19)
|
||||||
#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
|
#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
|
||||||
#define HID_QUIRK_NOINVERT BIT(21)
|
#define HID_QUIRK_NOINVERT BIT(21)
|
||||||
|
#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)
|
||||||
#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)
|
#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)
|
||||||
#define HID_QUIRK_NO_INIT_REPORTS BIT(29)
|
#define HID_QUIRK_NO_INIT_REPORTS BIT(29)
|
||||||
#define HID_QUIRK_NO_IGNORE BIT(30)
|
#define HID_QUIRK_NO_IGNORE BIT(30)
|
||||||
@ -599,15 +601,17 @@ enum hid_battery_status {
|
|||||||
struct hid_driver;
|
struct hid_driver;
|
||||||
struct hid_ll_driver;
|
struct hid_ll_driver;
|
||||||
|
|
||||||
struct hid_device { /* device report descriptor */
|
struct hid_device {
|
||||||
const __u8 *dev_rdesc;
|
const __u8 *dev_rdesc; /* device report descriptor */
|
||||||
unsigned dev_rsize;
|
const __u8 *bpf_rdesc; /* bpf modified report descriptor, if any */
|
||||||
const __u8 *rdesc;
|
const __u8 *rdesc; /* currently used report descriptor */
|
||||||
unsigned rsize;
|
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 */
|
struct hid_collection *collection; /* List of HID collections */
|
||||||
unsigned collection_size; /* Number of allocated hid_collections */
|
unsigned int maxcollection; /* Number of parsed collections */
|
||||||
unsigned maxcollection; /* Number of parsed collections */
|
unsigned int maxapplication; /* Number of applications */
|
||||||
unsigned maxapplication; /* Number of applications */
|
|
||||||
__u16 bus; /* BUS ID */
|
__u16 bus; /* BUS ID */
|
||||||
__u16 group; /* Report group */
|
__u16 group; /* Report group */
|
||||||
__u32 vendor; /* Vendor ID */
|
__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_disconnect_device(struct hid_device *hdev);
|
||||||
void hid_bpf_destroy_device(struct hid_device *hid);
|
void hid_bpf_destroy_device(struct hid_device *hid);
|
||||||
int hid_bpf_device_init(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 */
|
#else /* CONFIG_HID_BPF */
|
||||||
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
|
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
|
||||||
u8 *data, u32 *size, int interrupt,
|
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_disconnect_device(struct hid_device *hdev) {}
|
||||||
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
|
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
|
||||||
static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
|
static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
|
||||||
/*
|
static inline const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc,
|
||||||
* This specialized allocator has to be a macro for its allocations to be
|
unsigned int *size) { return rdesc; }
|
||||||
* 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))
|
|
||||||
|
|
||||||
#endif /* CONFIG_HID_BPF */
|
#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 object $(<:.o=.linked1.o) $<
|
||||||
$(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.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,,$@)
|
$(call msg,CC,,$@)
|
||||||
$(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
|
$(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
@ -4,13 +4,6 @@
|
|||||||
#include "hid_common.h"
|
#include "hid_common.h"
|
||||||
#include <bpf/bpf.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 {
|
struct hid_hw_request_syscall_args {
|
||||||
__u8 data[10];
|
__u8 data[10];
|
||||||
unsigned int hid;
|
unsigned int hid;
|
||||||
@ -21,11 +14,8 @@ struct hid_hw_request_syscall_args {
|
|||||||
};
|
};
|
||||||
|
|
||||||
FIXTURE(hid_bpf) {
|
FIXTURE(hid_bpf) {
|
||||||
int dev_id;
|
struct uhid_device hid;
|
||||||
int uhid_fd;
|
|
||||||
int hidraw_fd;
|
int hidraw_fd;
|
||||||
int hid_id;
|
|
||||||
pthread_t tid;
|
|
||||||
struct hid *skel;
|
struct hid *skel;
|
||||||
struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */
|
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) {
|
FIXTURE_TEARDOWN(hid_bpf) {
|
||||||
void *uhid_err;
|
void *uhid_err;
|
||||||
|
|
||||||
uhid_destroy(_metadata, self->uhid_fd);
|
uhid_destroy(_metadata, &self->hid);
|
||||||
|
|
||||||
detach_bpf(self);
|
detach_bpf(self);
|
||||||
pthread_join(self->tid, &uhid_err);
|
pthread_join(self->hid.tid, &uhid_err);
|
||||||
}
|
}
|
||||||
#define TEARDOWN_LOG(fmt, ...) do { \
|
#define TEARDOWN_LOG(fmt, ...) do { \
|
||||||
TH_LOG(fmt, ##__VA_ARGS__); \
|
TH_LOG(fmt, ##__VA_ARGS__); \
|
||||||
hid_bpf_teardown(_metadata, self, variant); \
|
hid_bpf_teardown(_metadata, self, variant); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
struct specific_device {
|
||||||
|
const char test_name[64];
|
||||||
|
__u16 bus;
|
||||||
|
__u32 vid;
|
||||||
|
__u32 pid;
|
||||||
|
};
|
||||||
|
|
||||||
FIXTURE_SETUP(hid_bpf)
|
FIXTURE_SETUP(hid_bpf)
|
||||||
{
|
{
|
||||||
time_t t;
|
const struct specific_device *match = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* initialize random number generator */
|
const struct specific_device devices[] = {
|
||||||
srand((unsigned int)time(&t));
|
{
|
||||||
|
.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 */
|
err = setup_uhid(_metadata, &self->hid, match->bus, match->vid, match->pid,
|
||||||
self->hid_id = get_hid_id(self->dev_id);
|
rdesc, sizeof(rdesc));
|
||||||
ASSERT_GT(self->hid_id, 0)
|
ASSERT_OK(err);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct test_program {
|
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);
|
ops_hid_id = bpf_map__initial_value(map, NULL);
|
||||||
ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data");
|
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
|
/* 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);
|
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");
|
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +199,7 @@ TEST_F(hid_bpf, raw_event)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* check that hid_first_event() was executed */
|
||||||
ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1");
|
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));
|
memset(buf, 0, sizeof(buf));
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 47;
|
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 */
|
/* check that hid_first_event() was executed */
|
||||||
ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1");
|
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 */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -252,7 +259,7 @@ TEST_F(hid_bpf, subprog_raw_event)
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 47;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -303,7 +310,7 @@ TEST_F(hid_bpf, test_attach_detach)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -326,14 +333,14 @@ TEST_F(hid_bpf, test_attach_detach)
|
|||||||
/* detach the program */
|
/* detach the program */
|
||||||
detach_bpf(self);
|
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");
|
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||||
|
|
||||||
/* inject another event */
|
/* inject another event */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 47;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -352,7 +359,7 @@ TEST_F(hid_bpf, test_attach_detach)
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -382,7 +389,7 @@ TEST_F(hid_bpf, test_hid_change_report)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -412,7 +419,7 @@ TEST_F(hid_bpf, test_hid_user_input_report_call)
|
|||||||
|
|
||||||
LOAD_BPF;
|
LOAD_BPF;
|
||||||
|
|
||||||
args.hid = self->hid_id;
|
args.hid = self->hid.hid_id;
|
||||||
args.data[0] = 1; /* report ID */
|
args.data[0] = 1; /* report ID */
|
||||||
args.data[1] = 2; /* report ID */
|
args.data[1] = 2; /* report ID */
|
||||||
args.data[2] = 42; /* report ID */
|
args.data[2] = 42; /* report ID */
|
||||||
@ -458,7 +465,7 @@ TEST_F(hid_bpf, test_hid_user_output_report_call)
|
|||||||
|
|
||||||
LOAD_BPF;
|
LOAD_BPF;
|
||||||
|
|
||||||
args.hid = self->hid_id;
|
args.hid = self->hid.hid_id;
|
||||||
args.data[0] = 1; /* report ID */
|
args.data[0] = 1; /* report ID */
|
||||||
args.data[1] = 2; /* report ID */
|
args.data[1] = 2; /* report ID */
|
||||||
args.data[2] = 42; /* report ID */
|
args.data[2] = 42; /* report ID */
|
||||||
@ -506,7 +513,7 @@ TEST_F(hid_bpf, test_hid_user_raw_request_call)
|
|||||||
|
|
||||||
LOAD_BPF;
|
LOAD_BPF;
|
||||||
|
|
||||||
args.hid = self->hid_id;
|
args.hid = self->hid.hid_id;
|
||||||
args.data[0] = 1; /* report ID */
|
args.data[0] = 1; /* report ID */
|
||||||
|
|
||||||
prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request);
|
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 */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -565,7 +572,7 @@ TEST_F(hid_bpf, test_hid_filter_raw_request_call)
|
|||||||
/* detach the program */
|
/* detach the program */
|
||||||
detach_bpf(self);
|
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");
|
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||||
|
|
||||||
err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
|
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 */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -667,7 +674,7 @@ TEST_F(hid_bpf, test_hid_filter_output_report_call)
|
|||||||
/* detach the program */
|
/* detach the program */
|
||||||
detach_bpf(self);
|
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");
|
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||||
|
|
||||||
err = write(self->hidraw_fd, buf, 3);
|
err = write(self->hidraw_fd, buf, 3);
|
||||||
@ -742,7 +749,7 @@ TEST_F(hid_bpf, test_multiply_events_wq)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -780,7 +787,7 @@ TEST_F(hid_bpf, test_multiply_events)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -816,7 +823,7 @@ TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call)
|
|||||||
buf[1] = 2;
|
buf[1] = 2;
|
||||||
buf[2] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -867,7 +874,7 @@ TEST_F(hid_bpf, test_hid_attach_flags)
|
|||||||
|
|
||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -878,6 +885,54 @@ TEST_F(hid_bpf, test_hid_attach_flags)
|
|||||||
ASSERT_EQ(buf[3], 3);
|
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,
|
* Attach hid_rdesc_fixup to the given uhid device,
|
||||||
* retrieve and open the matching hidraw node,
|
* retrieve and open the matching hidraw node,
|
||||||
|
@ -19,6 +19,16 @@
|
|||||||
__typeof__(b) _b = (b); \
|
__typeof__(b) _b = (b); \
|
||||||
_a < _b ? _a : _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[] = {
|
static unsigned char rdesc[] = {
|
||||||
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
|
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
|
||||||
0x09, 0x21, /* Usage (Vendor Usage 0x21) */
|
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;
|
struct uhid_event ev;
|
||||||
char buf[25];
|
char buf[25];
|
||||||
@ -133,10 +145,10 @@ static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb)
|
|||||||
ev.type = UHID_CREATE;
|
ev.type = UHID_CREATE;
|
||||||
strcpy((char *)ev.u.create.name, buf);
|
strcpy((char *)ev.u.create.name, buf);
|
||||||
ev.u.create.rd_data = rdesc;
|
ev.u.create.rd_data = rdesc;
|
||||||
ev.u.create.rd_size = sizeof(rdesc);
|
ev.u.create.rd_size = rdesc_size;
|
||||||
ev.u.create.bus = BUS_USB;
|
ev.u.create.bus = bus;
|
||||||
ev.u.create.vendor = 0x0001;
|
ev.u.create.vendor = vid;
|
||||||
ev.u.create.product = 0x0a37;
|
ev.u.create.product = pid;
|
||||||
ev.u.create.version = 0;
|
ev.u.create.version = 0;
|
||||||
ev.u.create.country = 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);
|
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;
|
struct uhid_event ev;
|
||||||
|
|
||||||
memset(&ev, 0, sizeof(ev));
|
memset(&ev, 0, sizeof(ev));
|
||||||
ev.type = UHID_DESTROY;
|
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)
|
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;
|
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;
|
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);
|
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;
|
char target[20] = "";
|
||||||
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 phys[512];
|
char phys[512];
|
||||||
char uevent[1024];
|
char uevent[1024];
|
||||||
char temp[512];
|
char temp[512];
|
||||||
int fd, nread;
|
int fd, nread;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
snprintf(target, sizeof(target), "%04X:%04X:%04X.*", hid->bus, hid->vid, hid->pid);
|
||||||
|
|
||||||
if (fnmatch(target, dir->d_name, 0))
|
if (fnmatch(target, dir->d_name, 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -334,7 +331,7 @@ static bool match_sysfs_device(int dev_id, const char *workdir, struct dirent *d
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sprintf(phys, "PHYS=%d", dev_id);
|
sprintf(phys, "PHYS=%d", hid->dev_id);
|
||||||
|
|
||||||
nread = read(fd, temp, ARRAY_SIZE(temp));
|
nread = read(fd, temp, ARRAY_SIZE(temp));
|
||||||
if (nread > 0 && (strstr(temp, phys)) != NULL)
|
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;
|
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 *workdir = "/sys/devices/virtual/misc/uhid";
|
||||||
const char *str_id;
|
const char *str_id;
|
||||||
@ -360,10 +357,10 @@ static int get_hid_id(int dev_id)
|
|||||||
d = opendir(workdir);
|
d = opendir(workdir);
|
||||||
if (d) {
|
if (d) {
|
||||||
while ((dir = readdir(d)) != NULL) {
|
while ((dir = readdir(d)) != NULL) {
|
||||||
if (!match_sysfs_device(dev_id, workdir, dir))
|
if (!match_sysfs_device(hid, workdir, dir))
|
||||||
continue;
|
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);
|
found = (int)strtol(str_id, NULL, 16);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -377,7 +374,7 @@ static int get_hid_id(int dev_id)
|
|||||||
return found;
|
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";
|
const char *workdir = "/sys/devices/virtual/misc/uhid";
|
||||||
char sysfs[1024];
|
char sysfs[1024];
|
||||||
@ -394,7 +391,7 @@ static int get_hidraw(int dev_id)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
while ((dir = readdir(d)) != NULL) {
|
while ((dir = readdir(d)) != NULL) {
|
||||||
if (!match_sysfs_device(dev_id, workdir, dir))
|
if (!match_sysfs_device(hid, workdir, dir))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sprintf(sysfs, "%s/%s/hidraw", workdir, dir->d_name);
|
sprintf(sysfs, "%s/%s/hidraw", workdir, dir->d_name);
|
||||||
@ -421,12 +418,12 @@ static int get_hidraw(int dev_id)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_hidraw(int dev_id)
|
static int open_hidraw(struct uhid_device *hid)
|
||||||
{
|
{
|
||||||
int hidraw_number;
|
int hidraw_number;
|
||||||
char hidraw_path[64] = { 0 };
|
char hidraw_path[64] = { 0 };
|
||||||
|
|
||||||
hidraw_number = get_hidraw(dev_id);
|
hidraw_number = get_hidraw(hid);
|
||||||
if (hidraw_number < 0)
|
if (hidraw_number < 0)
|
||||||
return hidraw_number;
|
return hidraw_number;
|
||||||
|
|
||||||
@ -434,3 +431,44 @@ static int open_hidraw(int dev_id)
|
|||||||
sprintf(hidraw_path, "/dev/hidraw%d", hidraw_number);
|
sprintf(hidraw_path, "/dev/hidraw%d", hidraw_number);
|
||||||
return open(hidraw_path, O_RDWR | O_NONBLOCK);
|
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 */
|
#endif /* HIDIOCREVOKE */
|
||||||
|
|
||||||
FIXTURE(hidraw) {
|
FIXTURE(hidraw) {
|
||||||
int dev_id;
|
struct uhid_device hid;
|
||||||
int uhid_fd;
|
|
||||||
int hidraw_fd;
|
int hidraw_fd;
|
||||||
int hid_id;
|
|
||||||
pthread_t tid;
|
|
||||||
};
|
};
|
||||||
static void close_hidraw(FIXTURE_DATA(hidraw) * self)
|
static void close_hidraw(FIXTURE_DATA(hidraw) * self)
|
||||||
{
|
{
|
||||||
@ -25,10 +22,10 @@ static void close_hidraw(FIXTURE_DATA(hidraw) * self)
|
|||||||
FIXTURE_TEARDOWN(hidraw) {
|
FIXTURE_TEARDOWN(hidraw) {
|
||||||
void *uhid_err;
|
void *uhid_err;
|
||||||
|
|
||||||
uhid_destroy(_metadata, self->uhid_fd);
|
uhid_destroy(_metadata, &self->hid);
|
||||||
|
|
||||||
close_hidraw(self);
|
close_hidraw(self);
|
||||||
pthread_join(self->tid, &uhid_err);
|
pthread_join(self->hid.tid, &uhid_err);
|
||||||
}
|
}
|
||||||
#define TEARDOWN_LOG(fmt, ...) do { \
|
#define TEARDOWN_LOG(fmt, ...) do { \
|
||||||
TH_LOG(fmt, ##__VA_ARGS__); \
|
TH_LOG(fmt, ##__VA_ARGS__); \
|
||||||
@ -37,25 +34,12 @@ FIXTURE_TEARDOWN(hidraw) {
|
|||||||
|
|
||||||
FIXTURE_SETUP(hidraw)
|
FIXTURE_SETUP(hidraw)
|
||||||
{
|
{
|
||||||
time_t t;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* initialize random number generator */
|
err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc));
|
||||||
srand((unsigned int)time(&t));
|
ASSERT_OK(err);
|
||||||
|
|
||||||
self->dev_id = rand() % 1024;
|
self->hidraw_fd = open_hidraw(&self->hid);
|
||||||
|
|
||||||
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);
|
|
||||||
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +63,7 @@ TEST_F(hidraw, raw_event)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -101,7 +85,7 @@ TEST_F(hidraw, raw_event_revoked)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -117,7 +101,7 @@ TEST_F(hidraw, raw_event_revoked)
|
|||||||
/* inject one other event */
|
/* inject one other event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 43;
|
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 */
|
/* read the data from hidraw */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -161,7 +145,7 @@ TEST_F(hidraw, poll_revoked)
|
|||||||
/* inject one event */
|
/* inject one event */
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 42;
|
buf[1] = 42;
|
||||||
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
|
uhid_send_event(_metadata, &self->hid, buf, 6);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ready = poll(pfds, 1, 5000);
|
ready = poll(pfds, 1, 5000);
|
||||||
|
@ -598,3 +598,15 @@ SEC(".struct_ops.link")
|
|||||||
struct hid_bpf_ops test_infinite_loop_input_report = {
|
struct hid_bpf_ops test_infinite_loop_input_report = {
|
||||||
.hid_device_event = (void *)hid_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;
|
struct hid_device *hdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BIT(n) (1U << n)
|
||||||
|
|
||||||
#ifndef BPF_F_BEFORE
|
#ifndef BPF_F_BEFORE
|
||||||
#define BPF_F_BEFORE (1U << 3)
|
#define BPF_F_BEFORE BIT(3)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)
|
||||||
|
|
||||||
/* following are kfuncs exported by HID for HID-BPF */
|
/* following are kfuncs exported by HID for HID-BPF */
|
||||||
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
|
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
|
||||||
unsigned int offset,
|
unsigned int offset,
|
||||||
|
Loading…
Reference in New Issue
Block a user