mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
HID: Add introduction about HID for non-kernel programmers
Add an introduction about HID meant for the casual programmer that is trying either to fix his device or to understand what is going wrong. Signed-off-by: Marco Morandini <marco.morandini@polimi.it> Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
parent
1d7546042f
commit
2326dee41c
524
Documentation/hid/hidintro.rst
Normal file
524
Documentation/hid/hidintro.rst
Normal file
@ -0,0 +1,524 @@
|
||||
.. 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
|
||||
...
|
49
Documentation/hid/hidreport-parsing.rst
Normal file
49
Documentation/hid/hidreport-parsing.rst
Normal file
@ -0,0 +1,49 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
========================================
|
||||
Manual parsing of HID report descriptors
|
||||
========================================
|
||||
|
||||
Consider again the mouse HID report descriptor
|
||||
introduced in Documentation/hid/hidintro.rst::
|
||||
|
||||
$ 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
|
||||
|
||||
and try to parse it by hand.
|
||||
|
||||
Start with the first number, 0x05: it carries 2 bits for the
|
||||
length of the item, 2 bits for the type of the item and 4 bits for the
|
||||
function::
|
||||
|
||||
+----------+
|
||||
| 00000101 |
|
||||
+----------+
|
||||
^^
|
||||
---- Length of data (see HID spec 6.2.2.2)
|
||||
^^
|
||||
------ Type of the item (see HID spec 6.2.2.2, then jump to 6.2.2.7)
|
||||
^^^^
|
||||
--------- Function of the item (see HID spec 6.2.2.7, then HUT Sec 3)
|
||||
|
||||
In our case, the length is 1 byte, the type is ``Global`` and the
|
||||
function is ``Usage Page``, thus for parsing the value 0x01 in the second byte
|
||||
we need to refer to HUT Sec 3.
|
||||
|
||||
The second number is the actual data, and its meaning can be found in
|
||||
the HUT. We have a ``Usage Page``, thus we need to refer to HUT
|
||||
Sec. 3, "Usage Pages"; from there, one sees that ``0x01`` stands for
|
||||
``Generic Desktop Page``.
|
||||
|
||||
Moving now to the second two bytes, and following the same scheme,
|
||||
``0x09`` (i.e. ``00001001``) will be followed by one byte (``01``)
|
||||
and is a ``Local`` item (``10``). Thus, the meaning of the remaining four bits
|
||||
(``0000``) is given in the HID spec Sec. 6.2.2.8 "Local Items", so that
|
||||
we have a ``Usage``. From HUT, Sec. 4, "Generic Desktop Page", we see that
|
||||
0x02 stands for ``Mouse``.
|
||||
|
||||
The following numbers can be parsed in the same way.
|
@ -7,6 +7,7 @@ Human Interface Devices (HID)
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
hidintro
|
||||
hiddev
|
||||
hidraw
|
||||
hid-sensor
|
||||
|
@ -341,6 +341,29 @@ struct hid_item {
|
||||
*/
|
||||
#define MAX_USBHID_BOOT_QUIRKS 4
|
||||
|
||||
/**
|
||||
* DOC: HID quirks
|
||||
* | @HID_QUIRK_NOTOUCH:
|
||||
* | @HID_QUIRK_IGNORE: ignore this device
|
||||
* | @HID_QUIRK_NOGET:
|
||||
* | @HID_QUIRK_HIDDEV_FORCE:
|
||||
* | @HID_QUIRK_BADPAD:
|
||||
* | @HID_QUIRK_MULTI_INPUT:
|
||||
* | @HID_QUIRK_HIDINPUT_FORCE:
|
||||
* | @HID_QUIRK_ALWAYS_POLL:
|
||||
* | @HID_QUIRK_INPUT_PER_APP:
|
||||
* | @HID_QUIRK_X_INVERT:
|
||||
* | @HID_QUIRK_Y_INVERT:
|
||||
* | @HID_QUIRK_SKIP_OUTPUT_REPORTS:
|
||||
* | @HID_QUIRK_SKIP_OUTPUT_REPORT_ID:
|
||||
* | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP:
|
||||
* | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
|
||||
* | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
|
||||
* | @HID_QUIRK_FULLSPEED_INTERVAL:
|
||||
* | @HID_QUIRK_NO_INIT_REPORTS:
|
||||
* | @HID_QUIRK_NO_IGNORE:
|
||||
* | @HID_QUIRK_NO_INPUT_SYNC:
|
||||
*/
|
||||
/* BIT(0) reserved for backward compatibility, was HID_QUIRK_INVERT */
|
||||
#define HID_QUIRK_NOTOUCH BIT(1)
|
||||
#define HID_QUIRK_IGNORE BIT(2)
|
||||
|
Loading…
Reference in New Issue
Block a user