525 lines
20 KiB
ReStructuredText
525 lines
20 KiB
ReStructuredText
|
.. SPDX-License-Identifier: GPL-2.0
|
||
|
|
||
|
======================================
|
||
|
Introduction to HID report descriptors
|
||
|
======================================
|
||
|
|
||
|
This chapter is meant to give a broad overview of what HID report
|
||
|
descriptors are, and of how a casual (non-kernel) programmer can deal
|
||
|
with HID devices that are not working well with Linux.
|
||
|
|
||
|
.. contents::
|
||
|
:local:
|
||
|
:depth: 2
|
||
|
|
||
|
.. toctree::
|
||
|
:maxdepth: 2
|
||
|
|
||
|
hidreport-parsing
|
||
|
|
||
|
|
||
|
Introduction
|
||
|
============
|
||
|
|
||
|
HID stands for Human Interface Device, and can be whatever device you
|
||
|
are using to interact with a computer, be it a mouse, a touchpad, a
|
||
|
tablet, a microphone.
|
||
|
|
||
|
Many HID devices work out the box, even if their hardware is different.
|
||
|
For example, mice can have any number of buttons; they may have a
|
||
|
wheel; movement sensitivity differs between different models, and so
|
||
|
on. Nonetheless, most of the time everything just works, without the
|
||
|
need to have specialized code in the kernel for every mouse model
|
||
|
developed since 1970.
|
||
|
|
||
|
This is because modern HID devices do advertise their capabilities
|
||
|
through the *HID report descriptor*, a fixed set of bytes describing
|
||
|
exactly what *HID reports* may be sent between the device and the host
|
||
|
and the meaning of each individual bit in those reports. For example,
|
||
|
a HID Report Descriptor may specify that "in a report with ID 3 the
|
||
|
bits from 8 to 15 is the delta x coordinate of a mouse".
|
||
|
|
||
|
The HID report itself then merely carries the actual data values
|
||
|
without any extra meta information. Note that HID reports may be sent
|
||
|
from the device ("Input Reports", i.e. input events), to the device
|
||
|
("Output Reports" to e.g. change LEDs) or used for device configuration
|
||
|
("Feature reports"). A device may support one or more HID reports.
|
||
|
|
||
|
The HID subsystem is in charge of parsing the HID report descriptors,
|
||
|
and converts HID events into normal input device interfaces (see
|
||
|
Documentation/hid/hid-transport.rst). Devices may misbehave because the
|
||
|
HID report descriptor provided by the device is wrong, or because it
|
||
|
needs to be dealt with in a special way, or because some special
|
||
|
device or interaction mode is not handled by the default code.
|
||
|
|
||
|
The format of HID report descriptors is described by two documents,
|
||
|
available from the `USB Implementers Forum <https://www.usb.org/>`_
|
||
|
`HID web page <https://www.usb.org/hid>`_ address:
|
||
|
|
||
|
* the `HID USB Device Class Definition
|
||
|
<https://www.usb.org/document-library/device-class-definition-hid-111>`_ (HID Spec from now on)
|
||
|
* the `HID Usage Tables <https://usb.org/document-library/hid-usage-tables-14>`_ (HUT from now on)
|
||
|
|
||
|
The HID subsystem can deal with different transport drivers
|
||
|
(USB, I2C, Bluetooth, etc.). See Documentation/hid/hid-transport.rst.
|
||
|
|
||
|
Parsing HID report descriptors
|
||
|
==============================
|
||
|
|
||
|
The current list of HID devices can be found at ``/sys/bus/hid/devices/``.
|
||
|
For each device, say ``/sys/bus/hid/devices/0003\:093A\:2510.0002/``,
|
||
|
one can read the corresponding report descriptor::
|
||
|
|
||
|
$ hexdump -C /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
|
||
|
00000000 05 01 09 02 a1 01 09 01 a1 00 05 09 19 01 29 03 |..............).|
|
||
|
00000010 15 00 25 01 75 01 95 03 81 02 75 05 95 01 81 01 |..%.u.....u.....|
|
||
|
00000020 05 01 09 30 09 31 09 38 15 81 25 7f 75 08 95 03 |...0.1.8..%.u...|
|
||
|
00000030 81 06 c0 c0 |....|
|
||
|
00000034
|
||
|
|
||
|
Optional: the HID report descriptor can be read also by
|
||
|
directly accessing the hidraw driver [#hidraw]_.
|
||
|
|
||
|
The basic structure of HID report descriptors is defined in the HID
|
||
|
spec, while HUT "defines constants that can be interpreted by an
|
||
|
application to identify the purpose and meaning of a data field in a
|
||
|
HID report". Each entry is defined by at least two bytes, where the
|
||
|
first one defines what type of value is following and is described in
|
||
|
the HID spec, while the second one carries the actual value and is
|
||
|
described in the HUT.
|
||
|
|
||
|
HID report descriptors can, in principle, be painstakingly parsed by
|
||
|
hand, byte by byte.
|
||
|
|
||
|
A short introduction on how to do this is sketched in
|
||
|
Documentation/hid/hidreport-parsing.rst; you only need to understand it
|
||
|
if you need to patch HID report descriptors.
|
||
|
|
||
|
In practice you should not parse HID report descriptors by hand; rather,
|
||
|
you should use an existing parser. Among all the available ones
|
||
|
|
||
|
* the online `USB Descriptor and Request Parser
|
||
|
<http://eleccelerator.com/usbdescreqparser/>`_;
|
||
|
* `hidrdd <https://github.com/abend0c1/hidrdd>`_,
|
||
|
that provides very detailed and somewhat verbose descriptions
|
||
|
(verbosity can be useful if you are not familiar with HID report
|
||
|
descriptors);
|
||
|
* `hid-tools <https://gitlab.freedesktop.org/libevdev/hid-tools>`_,
|
||
|
a complete utility set that allows, among other things,
|
||
|
to record and replay the raw HID reports and to debug
|
||
|
and replay HID devices.
|
||
|
It is being actively developed by the Linux HID subsystem maintainers.
|
||
|
|
||
|
Parsing the mouse HID report descriptor with `hid-tools
|
||
|
<https://gitlab.freedesktop.org/libevdev/hid-tools>`_ leads to
|
||
|
(explanations interposed)::
|
||
|
|
||
|
$ ./hid-decode /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
|
||
|
# device 0:0
|
||
|
# 0x05, 0x01, // Usage Page (Generic Desktop) 0
|
||
|
# 0x09, 0x02, // Usage (Mouse) 2
|
||
|
# 0xa1, 0x01, // Collection (Application) 4
|
||
|
# 0x09, 0x01, // Usage (Pointer) 6
|
||
|
# 0xa1, 0x00, // Collection (Physical) 8
|
||
|
# 0x05, 0x09, // Usage Page (Button) 10
|
||
|
|
||
|
what follows is a button ::
|
||
|
|
||
|
# 0x19, 0x01, // Usage Minimum (1) 12
|
||
|
# 0x29, 0x03, // Usage Maximum (3) 14
|
||
|
|
||
|
first button is button number 1, last button is button number 3 ::
|
||
|
|
||
|
# 0x15, 0x00, // Logical Minimum (0) 16
|
||
|
# 0x25, 0x01, // Logical Maximum (1) 18
|
||
|
|
||
|
each button can send values from 0 up to including 1
|
||
|
(i.e. they are binary buttons) ::
|
||
|
|
||
|
# 0x75, 0x01, // Report Size (1) 20
|
||
|
|
||
|
each button is sent as exactly one bit ::
|
||
|
|
||
|
# 0x95, 0x03, // Report Count (3) 22
|
||
|
|
||
|
and there are three of those bits (matching the three buttons) ::
|
||
|
|
||
|
# 0x81, 0x02, // Input (Data,Var,Abs) 24
|
||
|
|
||
|
it's actual Data (not constant padding), they represent
|
||
|
a single variable (Var) and their values are Absolute (not relative);
|
||
|
See HID spec Sec. 6.2.2.5 "Input, Output, and Feature Items" ::
|
||
|
|
||
|
# 0x75, 0x05, // Report Size (5) 26
|
||
|
|
||
|
five additional padding bits, needed to reach a byte ::
|
||
|
|
||
|
# 0x95, 0x01, // Report Count (1) 28
|
||
|
|
||
|
those five bits are repeated only once ::
|
||
|
|
||
|
# 0x81, 0x01, // Input (Cnst,Arr,Abs) 30
|
||
|
|
||
|
and take Constant (Cnst) values i.e. they can be ignored. ::
|
||
|
|
||
|
# 0x05, 0x01, // Usage Page (Generic Desktop) 32
|
||
|
# 0x09, 0x30, // Usage (X) 34
|
||
|
# 0x09, 0x31, // Usage (Y) 36
|
||
|
# 0x09, 0x38, // Usage (Wheel) 38
|
||
|
|
||
|
The mouse has also two physical positions (Usage (X), Usage (Y))
|
||
|
and a wheel (Usage (Wheel)) ::
|
||
|
|
||
|
# 0x15, 0x81, // Logical Minimum (-127) 40
|
||
|
# 0x25, 0x7f, // Logical Maximum (127) 42
|
||
|
|
||
|
each of them can send values ranging from -127 up to including 127 ::
|
||
|
|
||
|
# 0x75, 0x08, // Report Size (8) 44
|
||
|
|
||
|
which is represented by eight bits ::
|
||
|
|
||
|
# 0x95, 0x03, // Report Count (3) 46
|
||
|
|
||
|
and there are three of those eight bits, matching X, Y and Wheel. ::
|
||
|
|
||
|
# 0x81, 0x06, // Input (Data,Var,Rel) 48
|
||
|
|
||
|
This time the data values are Relative (Rel), i.e. they represent
|
||
|
the change from the previously sent report (event) ::
|
||
|
|
||
|
# 0xc0, // End Collection 50
|
||
|
# 0xc0, // End Collection 51
|
||
|
#
|
||
|
R: 52 05 01 09 02 a1 01 09 01 a1 00 05 09 19 01 29 03 15 00 25 01 75 01 95 03 81 02 75 05 95 01 81 01 05 01 09 30 09 31 09 38 15 81 25 7f 75 08 95 03 81 06 c0 c0
|
||
|
N: device 0:0
|
||
|
I: 3 0001 0001
|
||
|
|
||
|
|
||
|
This Report Descriptor tells us that the mouse input will be
|
||
|
transmitted using four bytes: the first one for the buttons (three
|
||
|
bits used, five for padding), the last three for the mouse X, Y and
|
||
|
wheel changes, respectively.
|
||
|
|
||
|
Indeed, for any event, the mouse will send a *report* of four bytes.
|
||
|
We can check the values sent by resorting e.g. to the `hid-recorder`
|
||
|
tool, from `hid-tools <https://gitlab.freedesktop.org/libevdev/hid-tools>`_:
|
||
|
The sequence of bytes sent by clicking and releasing button 1, then button 2, then button 3 is::
|
||
|
|
||
|
$ sudo ./hid-recorder /dev/hidraw1
|
||
|
|
||
|
....
|
||
|
output of hid-decode
|
||
|
....
|
||
|
|
||
|
# Button: 1 0 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000000.000000 4 01 00 00 00
|
||
|
# Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000000.183949 4 00 00 00 00
|
||
|
# Button: 0 1 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000001.959698 4 02 00 00 00
|
||
|
# Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000002.103899 4 00 00 00 00
|
||
|
# Button: 0 0 1 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000004.855799 4 04 00 00 00
|
||
|
# Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000005.103864 4 00 00 00 00
|
||
|
|
||
|
This example shows that when button 2 is clicked,
|
||
|
the bytes ``02 00 00 00`` are sent, and the immediately subsequent
|
||
|
event (``00 00 00 00``) is the release of button 2 (no buttons are
|
||
|
pressed, remember that the data values are *absolute*).
|
||
|
|
||
|
If instead one clicks and holds button 1, then clicks and holds button
|
||
|
2, releases button 1, and finally releases button 2, the reports are::
|
||
|
|
||
|
# Button: 1 0 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000044.175830 4 01 00 00 00
|
||
|
# Button: 1 1 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000045.975997 4 03 00 00 00
|
||
|
# Button: 0 1 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000047.407930 4 02 00 00 00
|
||
|
# Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
|
||
|
E: 000049.199919 4 00 00 00 00
|
||
|
|
||
|
where with ``03 00 00 00`` both buttons are pressed, and with the
|
||
|
subsequent ``02 00 00 00`` button 1 is released while button 2 is still
|
||
|
active.
|
||
|
|
||
|
Output, Input and Feature Reports
|
||
|
---------------------------------
|
||
|
|
||
|
HID devices can have Input Reports, like in the mouse example, Output
|
||
|
Reports, and Feature Reports. "Output" means that the information is
|
||
|
sent to the device. For example, a joystick with force feedback will
|
||
|
have some output; the led of a keyboard would need an output as well.
|
||
|
"Input" means that data come from the device.
|
||
|
|
||
|
"Feature"s are not meant to be consumed by the end user and define
|
||
|
configuration options for the device. They can be queried from the host;
|
||
|
when declared as *Volatile* they should be changed by the host.
|
||
|
|
||
|
|
||
|
Collections, Report IDs and Evdev events
|
||
|
========================================
|
||
|
|
||
|
A single device can logically group data into different independent
|
||
|
sets, called a *Collection*. Collections can be nested and there are
|
||
|
different types of collections (see the HID spec 6.2.2.6
|
||
|
"Collection, End Collection Items" for details).
|
||
|
|
||
|
Different reports are identified by means of different *Report ID*
|
||
|
fields, i.e. a number identifying the structure of the immediately
|
||
|
following report.
|
||
|
Whenever a Report ID is needed it is transmitted as the first byte of
|
||
|
any report. A device with only one supported HID report (like the mouse
|
||
|
example above) may omit the report ID.
|
||
|
|
||
|
Consider the following HID report descriptor::
|
||
|
|
||
|
05 01 09 02 A1 01 85 01 05 09 19 01 29 05 15 00
|
||
|
25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01
|
||
|
09 30 09 31 16 00 F8 26 FF 07 75 0C 95 02 81 06
|
||
|
09 38 15 80 25 7F 75 08 95 01 81 06 05 0C 0A 38
|
||
|
02 15 80 25 7F 75 08 95 01 81 06 C0 05 01 09 02
|
||
|
A1 01 85 02 05 09 19 01 29 05 15 00 25 01 95 05
|
||
|
75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31
|
||
|
16 00 F8 26 FF 07 75 0C 95 02 81 06 09 38 15 80
|
||
|
25 7F 75 08 95 01 81 06 05 0C 0A 38 02 15 80 25
|
||
|
7F 75 08 95 01 81 06 C0 05 01 09 07 A1 01 85 05
|
||
|
05 07 15 00 25 01 09 29 09 3E 09 4B 09 4E 09 E3
|
||
|
09 E8 09 E8 09 E8 75 01 95 08 81 02 95 00 81 01
|
||
|
C0 05 0C 09 01 A1 01 85 06 15 00 25 01 75 01 95
|
||
|
01 09 3F 81 06 09 3F 81 06 09 3F 81 06 09 3F 81
|
||
|
06 09 3F 81 06 09 3F 81 06 09 3F 81 06 09 3F 81
|
||
|
06 C0 05 0C 09 01 A1 01 85 03 09 05 15 00 26 FF
|
||
|
00 75 08 95 02 B1 02 C0
|
||
|
|
||
|
After parsing it (try to parse it on your own using the suggested
|
||
|
tools!) one can see that the device presents two ``Mouse`` Application
|
||
|
Collections (with reports identified by Reports IDs 1 and 2,
|
||
|
respectively), a ``Keypad`` Application Collection (whose report is
|
||
|
identified by the Report ID 5) and two ``Consumer Controls`` Application
|
||
|
Collections, (with Report IDs 6 and 3, respectively). Note, however,
|
||
|
that a device can have different Report IDs for the same Application
|
||
|
Collection.
|
||
|
|
||
|
The data sent will begin with the Report ID byte, and will be followed
|
||
|
by the corresponding information. For example, the data transmitted for
|
||
|
the last consumer control::
|
||
|
|
||
|
0x05, 0x0C, // Usage Page (Consumer)
|
||
|
0x09, 0x01, // Usage (Consumer Control)
|
||
|
0xA1, 0x01, // Collection (Application)
|
||
|
0x85, 0x03, // Report ID (3)
|
||
|
0x09, 0x05, // Usage (Headphone)
|
||
|
0x15, 0x00, // Logical Minimum (0)
|
||
|
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||
|
0x75, 0x08, // Report Size (8)
|
||
|
0x95, 0x02, // Report Count (2)
|
||
|
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||
|
0xC0, // End Collection
|
||
|
|
||
|
will be of three bytes: the first for the Report ID (3), the next two
|
||
|
for the headphone, with two (``Report Count (2)``) bytes
|
||
|
(``Report Size (8)``), each ranging from 0 (``Logical Minimum (0)``)
|
||
|
to 255 (``Logical Maximum (255)``).
|
||
|
|
||
|
All the Input data sent by the device should be translated into
|
||
|
corresponding Evdev events, so that the remaining part of the stack can
|
||
|
know what is going on, e.g. the bit for the first button translates into
|
||
|
the ``EV_KEY/BTN_LEFT`` evdev event and relative X movement translates
|
||
|
into the ``EV_REL/REL_X`` evdev event".
|
||
|
|
||
|
Events
|
||
|
======
|
||
|
|
||
|
In Linux, one ``/dev/input/event*`` is created for each ``Application
|
||
|
Collection``. Going back to the mouse example, and repeating the
|
||
|
sequence where one clicks and holds button 1, then clicks and holds
|
||
|
button 2, releases button 1, and finally releases button 2, one gets::
|
||
|
|
||
|
$ sudo libinput record /dev/input/event1
|
||
|
# libinput record
|
||
|
version: 1
|
||
|
ndevices: 1
|
||
|
libinput:
|
||
|
version: "1.23.0"
|
||
|
git: "unknown"
|
||
|
system:
|
||
|
os: "opensuse-tumbleweed:20230619"
|
||
|
kernel: "6.3.7-1-default"
|
||
|
dmi: "dmi:bvnHP:bvrU77Ver.01.05.00:bd03/24/2022:br5.0:efr20.29:svnHP:pnHPEliteBook64514inchG9NotebookPC:pvr:rvnHP:rn89D2:rvrKBCVersion14.1D.00:cvnHP:ct10:cvr:sku5Y3J1EA#ABZ:"
|
||
|
devices:
|
||
|
- node: /dev/input/event1
|
||
|
evdev:
|
||
|
# Name: PixArt HP USB Optical Mouse
|
||
|
# ID: bus 0x3 vendor 0x3f0 product 0x94a version 0x111
|
||
|
# Supported Events:
|
||
|
# Event type 0 (EV_SYN)
|
||
|
# Event type 1 (EV_KEY)
|
||
|
# Event code 272 (BTN_LEFT)
|
||
|
# Event code 273 (BTN_RIGHT)
|
||
|
# Event code 274 (BTN_MIDDLE)
|
||
|
# Event type 2 (EV_REL)
|
||
|
# Event code 0 (REL_X)
|
||
|
# Event code 1 (REL_Y)
|
||
|
# Event code 8 (REL_WHEEL)
|
||
|
# Event code 11 (REL_WHEEL_HI_RES)
|
||
|
# Event type 4 (EV_MSC)
|
||
|
# Event code 4 (MSC_SCAN)
|
||
|
# Properties:
|
||
|
name: "PixArt HP USB Optical Mouse"
|
||
|
id: [3, 1008, 2378, 273]
|
||
|
codes:
|
||
|
0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] # EV_SYN
|
||
|
1: [272, 273, 274] # EV_KEY
|
||
|
2: [0, 1, 8, 11] # EV_REL
|
||
|
4: [4] # EV_MSC
|
||
|
properties: []
|
||
|
hid: [
|
||
|
0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
|
||
|
0x15, 0x00, 0x25, 0x01, 0x95, 0x08, 0x75, 0x01, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31,
|
||
|
0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 0xc0, 0xc0
|
||
|
]
|
||
|
udev:
|
||
|
properties:
|
||
|
- ID_INPUT=1
|
||
|
- ID_INPUT_MOUSE=1
|
||
|
- LIBINPUT_DEVICE_GROUP=3/3f0/94a:usb-0000:05:00.3-2
|
||
|
quirks:
|
||
|
events:
|
||
|
# Current time is 12:31:56
|
||
|
- evdev:
|
||
|
- [ 0, 0, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
|
||
|
- [ 0, 0, 1, 272, 1] # EV_KEY / BTN_LEFT 1
|
||
|
- [ 0, 0, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +0ms
|
||
|
- evdev:
|
||
|
- [ 1, 207892, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
|
||
|
- [ 1, 207892, 1, 273, 1] # EV_KEY / BTN_RIGHT 1
|
||
|
- [ 1, 207892, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +1207ms
|
||
|
- evdev:
|
||
|
- [ 2, 367823, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
|
||
|
- [ 2, 367823, 1, 272, 0] # EV_KEY / BTN_LEFT 0
|
||
|
- [ 2, 367823, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +1160ms
|
||
|
# Current time is 12:32:00
|
||
|
- evdev:
|
||
|
- [ 3, 247617, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
|
||
|
- [ 3, 247617, 1, 273, 0] # EV_KEY / BTN_RIGHT 0
|
||
|
- [ 3, 247617, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +880ms
|
||
|
|
||
|
Note: if ``libinput record`` is not available on your system try using
|
||
|
``evemu-record``.
|
||
|
|
||
|
When something does not work
|
||
|
============================
|
||
|
|
||
|
There can be a number of reasons why a device does not behave
|
||
|
correctly. For example
|
||
|
|
||
|
* The HID report descriptor provided by the HID device may be wrong
|
||
|
because e.g.
|
||
|
|
||
|
* it does not follow the standard, so that the kernel
|
||
|
will not able to make sense of the HID report descriptor;
|
||
|
* the HID report descriptor *does not match* what is actually
|
||
|
sent by the device (this can be verified by reading the raw HID
|
||
|
data);
|
||
|
* the HID report descriptor may need some "quirks" (see later on).
|
||
|
|
||
|
As a consequence, a ``/dev/input/event*`` may not be created
|
||
|
for each Application Collection, and/or the events
|
||
|
there may not match what you would expect.
|
||
|
|
||
|
|
||
|
Quirks
|
||
|
------
|
||
|
|
||
|
There are some known peculiarities of HID devices that the kernel
|
||
|
knows how to fix - these are called the HID quirks and a list of those
|
||
|
is available in `include/linux/hid.h`.
|
||
|
|
||
|
Should this be the case, it should be enough to add the required quirk
|
||
|
in the kernel, for the HID device at hand. This can be done in the file
|
||
|
`drivers/hid/hid-quirks.c`. How to do it should be relatively
|
||
|
straightforward after looking into the file.
|
||
|
|
||
|
The list of currently defined quirks, from `include/linux/hid.h`, is
|
||
|
|
||
|
.. kernel-doc:: include/linux/hid.h
|
||
|
:doc: HID quirks
|
||
|
|
||
|
Quirks for USB devices can be specified while loading the usbhid module,
|
||
|
see ``modinfo usbhid``, although the proper fix should go into
|
||
|
hid-quirks.c and **be submitted upstream**.
|
||
|
See Documentation/process/submitting-patches.rst for guidelines on how
|
||
|
to submit a patch. Quirks for other busses need to go into hid-quirks.c.
|
||
|
|
||
|
Fixing HID report descriptors
|
||
|
-----------------------------
|
||
|
|
||
|
Should you need to patch HID report descriptors the easiest way is to
|
||
|
resort to eBPF, as described in Documentation/hid/hid-bpf.rst.
|
||
|
|
||
|
Basically, you can change any byte of the original HID report
|
||
|
descriptor. The examples in samples/hid should be a good starting point
|
||
|
for your code, see e.g. `samples/hid/hid_mouse.bpf.c`::
|
||
|
|
||
|
SEC("fmod_ret/hid_bpf_rdesc_fixup")
|
||
|
int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
|
||
|
{
|
||
|
....
|
||
|
data[39] = 0x31;
|
||
|
data[41] = 0x30;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
Of course this can be also done within the kernel source code, see e.g.
|
||
|
`drivers/hid/hid-aureal.c` or `drivers/hid/hid-samsung.c` for a slightly
|
||
|
more complex file.
|
||
|
|
||
|
Check Documentation/hid/hidreport-parsing.rst if you need any help
|
||
|
navigating the HID manuals and understanding the exact meaning of
|
||
|
the HID report descriptor hex numbers.
|
||
|
|
||
|
Whatever solution you come up with, please remember to **submit the
|
||
|
fix to the HID maintainers**, so that it can be directly integrated in
|
||
|
the kernel and that particular HID device will start working for
|
||
|
everyone else. See Documentation/process/submitting-patches.rst for
|
||
|
guidelines on how to do this.
|
||
|
|
||
|
|
||
|
Modifying the transmitted data on the fly
|
||
|
-----------------------------------------
|
||
|
|
||
|
Using eBPF it is also possible to modify the data exchanged with the
|
||
|
device. See again the examples in `samples/hid`.
|
||
|
|
||
|
Again, **please post your fix**, so that it can be integrated in the
|
||
|
kernel!
|
||
|
|
||
|
Writing a specialized driver
|
||
|
----------------------------
|
||
|
|
||
|
This should really be your last resort.
|
||
|
|
||
|
|
||
|
.. rubric:: Footnotes
|
||
|
|
||
|
.. [#hidraw] read hidraw: see Documentation/hid/hidraw.rst and
|
||
|
file `samples/hidraw/hid-example.c` for an example.
|
||
|
The output of ``hid-example`` would be, for the same mouse::
|
||
|
|
||
|
$ sudo ./hid-example
|
||
|
Report Descriptor Size: 52
|
||
|
Report Descriptor:
|
||
|
5 1 9 2 a1 1 9 1 a1 0 5 9 19 1 29 3 15 0 25 1 75 1 95 3 81 2 75 5 95 1 81 1 5 1 9 30 9 31 9 38 15 81 25 7f 75 8 95 3 81 6 c0 c0
|
||
|
|
||
|
Raw Name: PixArt USB Optical Mouse
|
||
|
Raw Phys: usb-0000:05:00.4-2.3/input0
|
||
|
Raw Info:
|
||
|
bustype: 3 (USB)
|
||
|
vendor: 0x093a
|
||
|
product: 0x2510
|
||
|
...
|