← Documents Documentation/hid/hidintro.rst GitHub 원문 ↗

Linux 6.18.37 · HID

Introduction to HID report descriptors

HID descriptor의 item·usage·field·collection·report ID 해석과 Linux debugging·수정 절차를 설명합니다.

Source pathDocumentation/hid/hidintro.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

hidintro.rst:1-524

HID report descriptor는 runtime report의 각 bit를 usage와 값 범위, 방향, absolute·relative semantics에 연결합니다. 이 문서는 mouse descriptor를 byte 단위로 해석하고 raw report, evdev event, quirk와 HID-BPF 수정까지 이어지는 실전 조사 절차를 제공합니다.

문서 위치
항목
SourceDocumentation/hid/hidintro.rst
분량524 source lines
Inspectionsysfs · hidraw · hid-tools
구조Usage · field · Collection · Report ID
수정HID quirk · HID-BPF · kernel driver

Source와 핵심 도구·개념입니다.

HID debugging 전체 경로
Sysfs에서 report descriptor 추출hid-decode로 item·usage 해석hid-recorder로 raw report 수집libinput record로 evdev mapping 확인Quirk 또는 HID-BPF fix 작성재검증 후 upstream 제출

Descriptor와 실제 data를 함께 검증합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ======================================
4 Introduction to HID report descriptors
5 ======================================
6
7 This chapter is meant to give a broad overview of what HID report
8 descriptors are, and of how a casual (non-kernel) programmer can deal
9 with HID devices that are not working well with Linux.
10
11 .. contents::
12 :local:
13 :depth: 2
14
15 .. toctree::
16 :maxdepth: 2
17
18 hidreport-parsing
19
20
21 Introduction
22 ============
23
24 HID stands for Human Interface Device, and can be whatever device you
25 are using to interact with a computer, be it a mouse, a touchpad, a
26 tablet, a microphone.
27
28 Many HID devices work out the box, even if their hardware is different.
29 For example, mice can have any number of buttons; they may have a
30 wheel; movement sensitivity differs between different models, and so
31 on. Nonetheless, most of the time everything just works, without the
32 need to have specialized code in the kernel for every mouse model
33 developed since 1970.
34
35 This is because modern HID devices do advertise their capabilities
36 through the *HID report descriptor*, a fixed set of bytes describing
37 exactly what *HID reports* may be sent between the device and the host
38 and the meaning of each individual bit in those reports. For example,
39 a HID Report Descriptor may specify that "in a report with ID 3 the
40 bits from 8 to 15 is the delta x coordinate of a mouse".
41
42 The HID report itself then merely carries the actual data values
43 without any extra meta information. Note that HID reports may be sent
44 from the device ("Input Reports", i.e. input events), to the device
45 ("Output Reports" to e.g. change LEDs) or used for device configuration
46 ("Feature reports"). A device may support one or more HID reports.
47
48 The HID subsystem is in charge of parsing the HID report descriptors,
49 and converts HID events into normal input device interfaces (see
50 Documentation/hid/hid-transport.rst). Devices may misbehave because the
51 HID report descriptor provided by the device is wrong, or because it
52 needs to be dealt with in a special way, or because some special
53 device or interaction mode is not handled by the default code.
54
55 The format of HID report descriptors is described by two documents,
56 available from the `USB Implementers Forum <https://www.usb.org/>`_
57 `HID web page <https://www.usb.org/hid>`_ address:
58
59 * the `HID USB Device Class Definition
60 <https://www.usb.org/document-library/device-class-definition-hid-111>`_ (HID Spec from now on)
61 * the `HID Usage Tables <https://usb.org/document-library/hid-usage-tables-14>`_ (HUT from now on)
62
63 The HID subsystem can deal with different transport drivers
64 (USB, I2C, Bluetooth, etc.). See Documentation/hid/hid-transport.rst.
65
66 Parsing HID report descriptors
67 ==============================
68
69 The current list of HID devices can be found at ``/sys/bus/hid/devices/``.
70 For each device, say ``/sys/bus/hid/devices/0003\:093A\:2510.0002/``,
71 one can read the corresponding report descriptor::
72
73 $ hexdump -C /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
74 00000000 05 01 09 02 a1 01 09 01 a1 00 05 09 19 01 29 03 |..............).|
75 00000010 15 00 25 01 75 01 95 03 81 02 75 05 95 01 81 01 |..%.u.....u.....|
76 00000020 05 01 09 30 09 31 09 38 15 81 25 7f 75 08 95 03 |...0.1.8..%.u...|
77 00000030 81 06 c0 c0 |....|
78 00000034
79
80 Optional: the HID report descriptor can be read also by
81 directly accessing the hidraw driver [#hidraw]_.
82
83 The basic structure of HID report descriptors is defined in the HID
84 spec, while HUT "defines constants that can be interpreted by an
85 application to identify the purpose and meaning of a data field in a
86 HID report". Each entry is defined by at least two bytes, where the
87 first one defines what type of value is following and is described in
88 the HID spec, while the second one carries the actual value and is
89 described in the HUT.
90
91 HID report descriptors can, in principle, be painstakingly parsed by
92 hand, byte by byte.
93
94 A short introduction on how to do this is sketched in
95 Documentation/hid/hidreport-parsing.rst; you only need to understand it
96 if you need to patch HID report descriptors.
97
98 In practice you should not parse HID report descriptors by hand; rather,
99 you should use an existing parser. Among all the available ones
100
101 * the online `USB Descriptor and Request Parser
102 <http://eleccelerator.com/usbdescreqparser/>`_;
103 * `hidrdd <https://github.com/abend0c1/hidrdd>`_,
104 that provides very detailed and somewhat verbose descriptions
105 (verbosity can be useful if you are not familiar with HID report
106 descriptors);
107 * `hid-tools <https://gitlab.freedesktop.org/libevdev/hid-tools>`_,
108 a complete utility set that allows, among other things,
109 to record and replay the raw HID reports and to debug
110 and replay HID devices.
111 It is being actively developed by the Linux HID subsystem maintainers.
112
113 Parsing the mouse HID report descriptor with `hid-tools
114 <https://gitlab.freedesktop.org/libevdev/hid-tools>`_ leads to
115 (explanations interposed)::
116
117 $ ./hid-decode /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
118 # device 0:0
119 # 0x05, 0x01, // Usage Page (Generic Desktop) 0
120 # 0x09, 0x02, // Usage (Mouse) 2
121 # 0xa1, 0x01, // Collection (Application) 4
122 # 0x09, 0x01, // Usage (Pointer) 6
123 # 0xa1, 0x00, // Collection (Physical) 8
124 # 0x05, 0x09, // Usage Page (Button) 10
125
126 what follows is a button ::
127
128 # 0x19, 0x01, // Usage Minimum (1) 12
129 # 0x29, 0x03, // Usage Maximum (3) 14
130
131 first button is button number 1, last button is button number 3 ::
132
133 # 0x15, 0x00, // Logical Minimum (0) 16
134 # 0x25, 0x01, // Logical Maximum (1) 18
135
136 each button can send values from 0 up to including 1
137 (i.e. they are binary buttons) ::
138
139 # 0x75, 0x01, // Report Size (1) 20
140
141 each button is sent as exactly one bit ::
142
143 # 0x95, 0x03, // Report Count (3) 22
144
145 and there are three of those bits (matching the three buttons) ::
146
147 # 0x81, 0x02, // Input (Data,Var,Abs) 24
148
149 it's actual Data (not constant padding), they represent
150 a single variable (Var) and their values are Absolute (not relative);
151 See HID spec Sec. 6.2.2.5 "Input, Output, and Feature Items" ::
152
153 # 0x75, 0x05, // Report Size (5) 26
154
155 five additional padding bits, needed to reach a byte ::
156
157 # 0x95, 0x01, // Report Count (1) 28
158
159 those five bits are repeated only once ::
160
161 # 0x81, 0x01, // Input (Cnst,Arr,Abs) 30
162
163 and take Constant (Cnst) values i.e. they can be ignored. ::
164
165 # 0x05, 0x01, // Usage Page (Generic Desktop) 32
166 # 0x09, 0x30, // Usage (X) 34
167 # 0x09, 0x31, // Usage (Y) 36
168 # 0x09, 0x38, // Usage (Wheel) 38
169
170 The mouse has also two physical positions (Usage (X), Usage (Y))
171 and a wheel (Usage (Wheel)) ::
172
173 # 0x15, 0x81, // Logical Minimum (-127) 40
174 # 0x25, 0x7f, // Logical Maximum (127) 42
175
176 each of them can send values ranging from -127 up to including 127 ::
177
178 # 0x75, 0x08, // Report Size (8) 44
179
180 which is represented by eight bits ::
181
182 # 0x95, 0x03, // Report Count (3) 46
183
184 and there are three of those eight bits, matching X, Y and Wheel. ::
185
186 # 0x81, 0x06, // Input (Data,Var,Rel) 48
187
188 This time the data values are Relative (Rel), i.e. they represent
189 the change from the previously sent report (event) ::
190
191 # 0xc0, // End Collection 50
192 # 0xc0, // End Collection 51
193 #
194 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
195 N: device 0:0
196 I: 3 0001 0001
197
198
199 This Report Descriptor tells us that the mouse input will be
200 transmitted using four bytes: the first one for the buttons (three
201 bits used, five for padding), the last three for the mouse X, Y and
202 wheel changes, respectively.
203
204 Indeed, for any event, the mouse will send a *report* of four bytes.
205 We can check the values sent by resorting e.g. to the `hid-recorder`
206 tool, from `hid-tools <https://gitlab.freedesktop.org/libevdev/hid-tools>`_:
207 The sequence of bytes sent by clicking and releasing button 1, then button 2, then button 3 is::
208
209 $ sudo ./hid-recorder /dev/hidraw1
210
211 ....
212 output of hid-decode
213 ....
214
215 # Button: 1 0 0 | # | X: 0 | Y: 0 | Wheel: 0
216 E: 000000.000000 4 01 00 00 00
217 # Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
218 E: 000000.183949 4 00 00 00 00
219 # Button: 0 1 0 | # | X: 0 | Y: 0 | Wheel: 0
220 E: 000001.959698 4 02 00 00 00
221 # Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
222 E: 000002.103899 4 00 00 00 00
223 # Button: 0 0 1 | # | X: 0 | Y: 0 | Wheel: 0
224 E: 000004.855799 4 04 00 00 00
225 # Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
226 E: 000005.103864 4 00 00 00 00
227
228 This example shows that when button 2 is clicked,
229 the bytes ``02 00 00 00`` are sent, and the immediately subsequent
230 event (``00 00 00 00``) is the release of button 2 (no buttons are
231 pressed, remember that the data values are *absolute*).
232
233 If instead one clicks and holds button 1, then clicks and holds button
234 2, releases button 1, and finally releases button 2, the reports are::
235
236 # Button: 1 0 0 | # | X: 0 | Y: 0 | Wheel: 0
237 E: 000044.175830 4 01 00 00 00
238 # Button: 1 1 0 | # | X: 0 | Y: 0 | Wheel: 0
239 E: 000045.975997 4 03 00 00 00
240 # Button: 0 1 0 | # | X: 0 | Y: 0 | Wheel: 0
241 E: 000047.407930 4 02 00 00 00
242 # Button: 0 0 0 | # | X: 0 | Y: 0 | Wheel: 0
243 E: 000049.199919 4 00 00 00 00
244
245 where with ``03 00 00 00`` both buttons are pressed, and with the
246 subsequent ``02 00 00 00`` button 1 is released while button 2 is still
247 active.
248
249 Output, Input and Feature Reports
250 ---------------------------------
251
252 HID devices can have Input Reports, like in the mouse example, Output
253 Reports, and Feature Reports. "Output" means that the information is
254 sent to the device. For example, a joystick with force feedback will
255 have some output; the led of a keyboard would need an output as well.
256 "Input" means that data come from the device.
257
258 "Feature"s are not meant to be consumed by the end user and define
259 configuration options for the device. They can be queried from the host;
260 when declared as *Volatile* they should be changed by the host.
261
262
263 Collections, Report IDs and Evdev events
264 ========================================
265
266 A single device can logically group data into different independent
267 sets, called a *Collection*. Collections can be nested and there are
268 different types of collections (see the HID spec 6.2.2.6
269 "Collection, End Collection Items" for details).
270
271 Different reports are identified by means of different *Report ID*
272 fields, i.e. a number identifying the structure of the immediately
273 following report.
274 Whenever a Report ID is needed it is transmitted as the first byte of
275 any report. A device with only one supported HID report (like the mouse
276 example above) may omit the report ID.
277
278 Consider the following HID report descriptor::
279
280 05 01 09 02 A1 01 85 01 05 09 19 01 29 05 15 00
281 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01
282 09 30 09 31 16 00 F8 26 FF 07 75 0C 95 02 81 06
283 09 38 15 80 25 7F 75 08 95 01 81 06 05 0C 0A 38
284 02 15 80 25 7F 75 08 95 01 81 06 C0 05 01 09 02
285 A1 01 85 02 05 09 19 01 29 05 15 00 25 01 95 05
286 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31
287 16 00 F8 26 FF 07 75 0C 95 02 81 06 09 38 15 80
288 25 7F 75 08 95 01 81 06 05 0C 0A 38 02 15 80 25
289 7F 75 08 95 01 81 06 C0 05 01 09 07 A1 01 85 05
290 05 07 15 00 25 01 09 29 09 3E 09 4B 09 4E 09 E3
291 09 E8 09 E8 09 E8 75 01 95 08 81 02 95 00 81 01
292 C0 05 0C 09 01 A1 01 85 06 15 00 25 01 75 01 95
293 01 09 3F 81 06 09 3F 81 06 09 3F 81 06 09 3F 81
294 06 09 3F 81 06 09 3F 81 06 09 3F 81 06 09 3F 81
295 06 C0 05 0C 09 01 A1 01 85 03 09 05 15 00 26 FF
296 00 75 08 95 02 B1 02 C0
297
298 After parsing it (try to parse it on your own using the suggested
299 tools!) one can see that the device presents two ``Mouse`` Application
300 Collections (with reports identified by Reports IDs 1 and 2,
301 respectively), a ``Keypad`` Application Collection (whose report is
302 identified by the Report ID 5) and two ``Consumer Controls`` Application
303 Collections, (with Report IDs 6 and 3, respectively). Note, however,
304 that a device can have different Report IDs for the same Application
305 Collection.
306
307 The data sent will begin with the Report ID byte, and will be followed
308 by the corresponding information. For example, the data transmitted for
309 the last consumer control::
310
311 0x05, 0x0C, // Usage Page (Consumer)
312 0x09, 0x01, // Usage (Consumer Control)
313 0xA1, 0x01, // Collection (Application)
314 0x85, 0x03, // Report ID (3)
315 0x09, 0x05, // Usage (Headphone)
316 0x15, 0x00, // Logical Minimum (0)
317 0x26, 0xFF, 0x00, // Logical Maximum (255)
318 0x75, 0x08, // Report Size (8)
319 0x95, 0x02, // Report Count (2)
320 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
321 0xC0, // End Collection
322
323 will be of three bytes: the first for the Report ID (3), the next two
324 for the headphone, with two (``Report Count (2)``) bytes
325 (``Report Size (8)``), each ranging from 0 (``Logical Minimum (0)``)
326 to 255 (``Logical Maximum (255)``).
327
328 All the Input data sent by the device should be translated into
329 corresponding Evdev events, so that the remaining part of the stack can
330 know what is going on, e.g. the bit for the first button translates into
331 the ``EV_KEY/BTN_LEFT`` evdev event and relative X movement translates
332 into the ``EV_REL/REL_X`` evdev event".
333
334 Events
335 ======
336
337 In Linux, one ``/dev/input/event*`` is created for each ``Application
338 Collection``. Going back to the mouse example, and repeating the
339 sequence where one clicks and holds button 1, then clicks and holds
340 button 2, releases button 1, and finally releases button 2, one gets::
341
342 $ sudo libinput record /dev/input/event1
343 # libinput record
344 version: 1
345 ndevices: 1
346 libinput:
347 version: "1.23.0"
348 git: "unknown"
349 system:
350 os: "opensuse-tumbleweed:20230619"
351 kernel: "6.3.7-1-default"
352 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:"
353 devices:
354 - node: /dev/input/event1
355 evdev:
356 # Name: PixArt HP USB Optical Mouse
357 # ID: bus 0x3 vendor 0x3f0 product 0x94a version 0x111
358 # Supported Events:
359 # Event type 0 (EV_SYN)
360 # Event type 1 (EV_KEY)
361 # Event code 272 (BTN_LEFT)
362 # Event code 273 (BTN_RIGHT)
363 # Event code 274 (BTN_MIDDLE)
364 # Event type 2 (EV_REL)
365 # Event code 0 (REL_X)
366 # Event code 1 (REL_Y)
367 # Event code 8 (REL_WHEEL)
368 # Event code 11 (REL_WHEEL_HI_RES)
369 # Event type 4 (EV_MSC)
370 # Event code 4 (MSC_SCAN)
371 # Properties:
372 name: "PixArt HP USB Optical Mouse"
373 id: [3, 1008, 2378, 273]
374 codes:
375 0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] # EV_SYN
376 1: [272, 273, 274] # EV_KEY
377 2: [0, 1, 8, 11] # EV_REL
378 4: [4] # EV_MSC
379 properties: []
380 hid: [
381 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
382 0x15, 0x00, 0x25, 0x01, 0x95, 0x08, 0x75, 0x01, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31,
383 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 0xc0, 0xc0
384 ]
385 udev:
386 properties:
387 - ID_INPUT=1
388 - ID_INPUT_MOUSE=1
389 - LIBINPUT_DEVICE_GROUP=3/3f0/94a:usb-0000:05:00.3-2
390 quirks:
391 events:
392 # Current time is 12:31:56
393 - evdev:
394 - [ 0, 0, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
395 - [ 0, 0, 1, 272, 1] # EV_KEY / BTN_LEFT 1
396 - [ 0, 0, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +0ms
397 - evdev:
398 - [ 1, 207892, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
399 - [ 1, 207892, 1, 273, 1] # EV_KEY / BTN_RIGHT 1
400 - [ 1, 207892, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +1207ms
401 - evdev:
402 - [ 2, 367823, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
403 - [ 2, 367823, 1, 272, 0] # EV_KEY / BTN_LEFT 0
404 - [ 2, 367823, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +1160ms
405 # Current time is 12:32:00
406 - evdev:
407 - [ 3, 247617, 4, 4, 30] # EV_MSC / MSC_SCAN 30 (obfuscated)
408 - [ 3, 247617, 1, 273, 0] # EV_KEY / BTN_RIGHT 0
409 - [ 3, 247617, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +880ms
410
411 Note: if ``libinput record`` is not available on your system try using
412 ``evemu-record``.
413
414 When something does not work
415 ============================
416
417 There can be a number of reasons why a device does not behave
418 correctly. For example
419
420 * The HID report descriptor provided by the HID device may be wrong
421 because e.g.
422
423 * it does not follow the standard, so that the kernel
424 will not able to make sense of the HID report descriptor;
425 * the HID report descriptor *does not match* what is actually
426 sent by the device (this can be verified by reading the raw HID
427 data);
428 * the HID report descriptor may need some "quirks" (see later on).
429
430 As a consequence, a ``/dev/input/event*`` may not be created
431 for each Application Collection, and/or the events
432 there may not match what you would expect.
433
434
435 Quirks
436 ------
437
438 There are some known peculiarities of HID devices that the kernel
439 knows how to fix - these are called the HID quirks and a list of those
440 is available in `include/linux/hid.h`.
441
442 Should this be the case, it should be enough to add the required quirk
443 in the kernel, for the HID device at hand. This can be done in the file
444 `drivers/hid/hid-quirks.c`. How to do it should be relatively
445 straightforward after looking into the file.
446
447 The list of currently defined quirks, from `include/linux/hid.h`, is
448
449 .. kernel-doc:: include/linux/hid.h
450 :doc: HID quirks
451
452 Quirks for USB devices can be specified while loading the usbhid module,
453 see ``modinfo usbhid``, although the proper fix should go into
454 hid-quirks.c and **be submitted upstream**.
455 See Documentation/process/submitting-patches.rst for guidelines on how
456 to submit a patch. Quirks for other busses need to go into hid-quirks.c.
457
458 Fixing HID report descriptors
459 -----------------------------
460
461 Should you need to patch HID report descriptors the easiest way is to
462 resort to eBPF, as described in Documentation/hid/hid-bpf.rst.
463
464 Basically, you can change any byte of the original HID report
465 descriptor. The examples in samples/hid should be a good starting point
466 for your code, see e.g. `samples/hid/hid_mouse.bpf.c`::
467
468 SEC("fmod_ret/hid_bpf_rdesc_fixup")
469 int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
470 {
471 ....
472 data[39] = 0x31;
473 data[41] = 0x30;
474 return 0;
475 }
476
477 Of course this can be also done within the kernel source code, see e.g.
478 `drivers/hid/hid-aureal.c` or `drivers/hid/hid-samsung.c` for a slightly
479 more complex file.
480
481 Check Documentation/hid/hidreport-parsing.rst if you need any help
482 navigating the HID manuals and understanding the exact meaning of
483 the HID report descriptor hex numbers.
484
485 Whatever solution you come up with, please remember to **submit the
486 fix to the HID maintainers**, so that it can be directly integrated in
487 the kernel and that particular HID device will start working for
488 everyone else. See Documentation/process/submitting-patches.rst for
489 guidelines on how to do this.
490
491
492 Modifying the transmitted data on the fly
493 -----------------------------------------
494
495 Using eBPF it is also possible to modify the data exchanged with the
496 device. See again the examples in `samples/hid`.
497
498 Again, **please post your fix**, so that it can be integrated in the
499 kernel!
500
501 Writing a specialized driver
502 ----------------------------
503
504 This should really be your last resort.
505
506
507 .. rubric:: Footnotes
508
509 .. [#hidraw] read hidraw: see Documentation/hid/hidraw.rst and
510 file `samples/hidraw/hid-example.c` for an example.
511 The output of ``hid-example`` would be, for the same mouse::
512
513 $ sudo ./hid-example
514 Report Descriptor Size: 52
515 Report Descriptor:
516 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
517
518 Raw Name: PixArt USB Optical Mouse
519 Raw Phys: usb-0000:05:00.4-2.3/input0
520 Raw Info:
521 bustype: 3 (USB)
522 vendor: 0x093a
523 product: 0x2510
524 ...
525

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

HID report descriptor 개요

1-64

이 장은 HID report descriptor가 무엇인지 폭넓게 설명하고, Linux에서 제대로 동작하지 않는 HID device를 일반적인 비-kernel programmer가 다루는 방법을 소개합니다. 이어지는 상세 parsing 문서는 `hidreport-parsing`입니다.

HID는 Human Interface Device의 약자이며 mouse, touchpad, tablet, microphone처럼 computer와 상호작용하는 여러 device를 뜻합니다.

Hardware가 달라도 많은 HID device는 별도 설정 없이 동작합니다. Mouse는 button 수, wheel 유무, movement sensitivity가 서로 다르지만 1970년 이후의 모든 model마다 kernel 전용 code를 만들지 않아도 대부분 동작합니다.

그 이유는 현대 HID device가 고정 byte 집합인 HID report descriptor로 capability를 알리기 때문입니다. Descriptor는 device와 host 사이에서 주고받을 수 있는 HID report와 report의 각 bit 의미를 정확히 설명합니다. 예를 들어 report ID 3의 bit 8~15가 mouse X 좌표 변화량이라고 지정할 수 있습니다.

HID report 자체는 추가 metadata 없이 실제 data 값만 담습니다. Device에서 host로 오는 input event는 Input Report, host에서 device로 LED 등을 바꾸는 것은 Output Report, device 설정은 Feature Report입니다. Device는 report를 하나 이상 지원할 수 있습니다.

HID subsystem은 descriptor를 parse하고 HID event를 일반 input device interface로 변환합니다. Transport 설명은 `Documentation/hid/hid-transport.rst`에 있습니다.

Device가 잘못 동작하는 원인은 제공한 descriptor가 틀렸거나, device를 특별한 방식으로 다뤄야 하거나, 특수 device·interaction mode를 기본 code가 처리하지 못하기 때문일 수 있습니다.

Descriptor 형식은 USB Implementers Forum의 HID USB Device Class Definition, 이후 HID Spec이라 부르는 문서와 HID Usage Tables, 이후 HUT라 부르는 문서에 정의됩니다.

HID subsystem은 USB, I2C, Bluetooth 등 여러 transport driver를 처리할 수 있습니다.

Descriptor와 report의 역할
항목역할
HID report descriptorReport ID·field·bit 의미를 고정 byte로 기술
Input ReportDevice에서 host로 input event 전송
Output ReportHost에서 device로 LED·actuator state 전송
Feature ReportDevice 설정 조회·변경
HUTUsage 상수의 목적과 data field 의미 정의

Capability metadata와 runtime data를 구분합니다.

HID 공통 동작
Device가 report descriptor 제공HID core가 capability와 field layout parseRuntime report에서 bit field 추출Usage 의미를 input·output·feature로 해석일반 input interface 또는 device-specific path로 전달

다양한 hardware가 공통 kernel code를 사용하는 이유입니다.

.. 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.

Descriptor 읽기와 parser 선택

65-115

현재 HID device 목록은 `/sys/bus/hid/devices/`에 있습니다. 예시 device `/sys/bus/hid/devices/0003\:093A\:2510.0002/`의 `report_descriptor`를 `hexdump -C`로 읽을 수 있습니다.

$ 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

선택적으로 hidraw driver에 직접 접근해 descriptor를 읽을 수도 있습니다.

HID Spec은 descriptor의 기본 구조를 정의하고, HUT는 application이 HID report의 data field 목적과 의미를 식별할 수 있도록 해석 가능한 상수를 정의합니다.

각 entry는 최소 두 byte로 정의됩니다. 첫 byte는 뒤따르는 값의 type을 나타내며 HID Spec에 설명되어 있고, 둘째 byte는 실제 값을 담으며 HUT에 설명되어 있습니다.

원칙적으로 descriptor를 byte 단위로 수동 parse할 수 있습니다. 간단한 방법은 `Documentation/hid/hidreport-parsing.rst`에 있으며 descriptor를 patch해야 할 때만 이해하면 됩니다.

실제로는 수동 parse 대신 기존 parser를 사용해야 합니다. Online USB Descriptor and Request Parser, 상세하고 다소 장황한 설명을 제공하는 `hidrdd`, raw HID report 기록·재생과 HID device debugging·replay를 제공하는 `hid-tools`가 있습니다.

`hid-tools`는 완전한 utility set이며 Linux HID subsystem maintainer가 활발히 개발합니다. 다음 절은 이 도구의 `hid-decode`로 mouse descriptor를 해석합니다.

Descriptor parser
도구특징
USB Descriptor and Request ParserOnline parser
hidrdd매우 상세하고 verbose한 설명
hid-toolsDecode · raw record/replay · device debug/replay
hidreport-parsing.rstPatch가 필요할 때 수동 구조 이해

문서가 권장하는 도구와 쓰임새입니다.

Descriptor 조사
sysfs device directory 선택report_descriptor를 hexdump필요하면 hidraw로 직접 read기존 parser에 byte stream 입력HID Spec item type과 HUT usage 의미 결합

Sysfs에서 읽은 byte를 의미 있는 item으로 바꿉니다.


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)::

Mouse descriptor를 item별로 해독

116-197

`hid-decode` 출력은 먼저 Generic Desktop usage page, Mouse usage와 Application Collection을 선언하고, 그 안에서 Pointer usage의 Physical Collection을 엽니다. 이어 Button usage page로 전환합니다.

Usage Minimum 1과 Usage Maximum 3은 첫 button이 1, 마지막 button이 3임을 뜻합니다. Logical Minimum 0과 Logical Maximum 1은 각 button이 0 또는 1의 binary 값을 보냄을 뜻합니다.

Report Size 1은 button 하나가 정확히 1bit임을 나타내고 Report Count 3은 세 button에 대응하는 bit 세 개가 있음을 나타냅니다.

`Input (Data,Var,Abs)`는 constant padding이 아닌 실제 data이고, 각 bit가 하나의 variable을 나타내며 값이 relative가 아니라 absolute임을 뜻합니다. 자세한 flag는 HID Spec 6.2.2.5를 참조합니다.

다음 Report Size 5, Report Count 1, `Input (Cnst,Arr,Abs)`는 byte 경계를 맞추는 5bit padding 하나를 정의합니다. Constant 값이므로 무시할 수 있습니다.

Generic Desktop page로 돌아와 X, Y, Wheel usage를 선언합니다. 각 값의 logical range는 -127~127이고 Report Size는 8bit, Report Count는 3이므로 X·Y·wheel 각각 1byte입니다.

이 field의 `Input (Data,Var,Rel)`은 이전 report에서의 변화량을 나타내는 relative data입니다. 마지막 두 `End Collection`이 Physical과 Application collection을 닫습니다.

`hid-decode`는 끝에 descriptor의 52byte raw sequence와 device metadata도 출력합니다.

Mouse 4-byte report layout
ByteBits의미속성
00..2Button 1..3Data · Variable · Absolute
03..7PaddingConstant
10..7X deltaData · Variable · Relative
20..7Y deltaData · Variable · Relative
30..7Wheel deltaData · Variable · Relative

Descriptor가 정의한 button·axis bit 배치입니다.

Descriptor item state
Usage Page와 Collection 선택Usage range 또는 X·Y·Wheel 지정Logical range 설정Report Size와 Count 설정Input item이 Data/Constant·Abs/Rel 확정End Collection으로 scope 종료

Global·local item이 다음 main item의 field를 정의합니다.


    $ ./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

4-byte mouse report의 실제 값

198-247

이 descriptor에 따르면 mouse input은 4byte로 전송됩니다. 첫 byte는 button으로 3bit를 사용하고 5bit는 padding이며, 나머지 세 byte는 각각 X, Y, wheel 변화량입니다.

실제 event마다 mouse는 4byte report를 보냅니다. `hid-tools`의 `hid-recorder`로 전송 값을 확인할 수 있습니다.

Button 1을 누르면 `01 00 00 00`, 놓으면 `00 00 00 00`이 나옵니다. Button 2는 `02 00 00 00`, button 3은 `04 00 00 00`입니다.

Button 2 click 직후의 `00 00 00 00`은 button 2 release입니다. Button data가 absolute이므로 bit가 0이면 그 시점에 button이 눌리지 않았음을 뜻합니다.

Button 1을 누른 채 button 2를 누르면 `03 00 00 00`으로 두 bit가 함께 설정됩니다. 그 뒤 button 1만 놓으면 `02 00 00 00`이 되어 button 2는 계속 active이고, 마지막 button 2 release는 `00 00 00 00`입니다.

Button 1 press:    01 00 00 00
Button 1 + 2:       03 00 00 00
Button 1 release:   02 00 00 00
Button 2 release:   00 00 00 00
Button 3 press:     04 00 00 00
Button bitmap
Button 1Button 2Button 3
0x00upupup
0x01downupup
0x02updownup
0x03downdownup
0x04upupdown

첫 byte의 absolute button state를 정리했습니다.

Press·release sequence
Button 1 press → 0x01Button 2 press 유지 추가 → 0x03Button 1 release → 0x02Button 2 release → 0x00각 report의 X·Y·wheel은 이 예에서 0

Absolute button bitmap이 누적 state를 표현합니다.


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.

Report type, Collection, Report ID와 evdev mapping

248-332

Mouse 예제처럼 device는 Input Report를 가질 수 있고 Output Report와 Feature Report도 가질 수 있습니다. Output은 host에서 device로 보내는 정보로 force-feedback joystick과 keyboard LED가 예입니다. Input은 device에서 오는 data입니다.

Feature는 end user가 소비하기 위한 것이 아니라 device configuration option을 정의합니다. Host가 query할 수 있으며 `Volatile`로 선언된 feature는 host가 변경해야 합니다.

하나의 device는 data를 Collection이라는 독립된 논리 집합으로 묶을 수 있습니다. Collection은 중첩 가능하고 여러 type이 있으며 HID Spec 6.2.2.6에 자세히 설명되어 있습니다.

서로 다른 report는 바로 뒤따르는 report 구조를 식별하는 숫자인 Report ID field로 구분됩니다. Report ID가 필요하면 모든 report의 첫 byte로 전송됩니다. Mouse 예처럼 report 하나만 지원하는 device는 ID를 생략할 수 있습니다.

제시된 긴 descriptor를 parse하면 Report ID 1과 2의 Mouse Application Collection 두 개, Report ID 5의 Keypad Application Collection, Report ID 6과 3의 Consumer Controls Application Collection 두 개가 있습니다. 같은 Application Collection이 서로 다른 Report ID를 가질 수도 있습니다.

Report data는 ID byte로 시작한 뒤 그 ID의 구조에 맞는 정보가 옵니다.

마지막 Consumer Control은 Consumer usage page, Consumer Control Application Collection, Report ID 3, Headphone usage를 선언합니다. Logical range는 0~255, Report Size는 8, Report Count는 2인 non-volatile Feature입니다.

따라서 이 report는 세 byte입니다. 첫 byte는 Report ID 3이고 다음 두 byte는 headphone field 두 개이며, 각각 0~255 범위입니다.

Device가 보내는 모든 Input data는 stack의 나머지 부분이 이해할 수 있도록 대응하는 evdev event로 변환되어야 합니다. 첫 button bit는 `EV_KEY/BTN_LEFT`, 상대 X movement는 `EV_REL/REL_X`로 변환됩니다.

Application Collection과 Report ID
CollectionReport ID
Mouse Application1
Mouse Application2
Keypad Application5
Consumer Controls Application6
Consumer Controls Application3

예제 descriptor를 parse한 결과입니다.

Report ID dispatch
Report 첫 byte에서 ID readID에 대응하는 Application Collection 선택Descriptor의 field size·count 적용Input usage를 evdev code로 mappingOutput·Feature는 방향과 목적에 맞게 처리

첫 byte가 뒤따르는 payload 구조를 선택합니다.


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".

Application Collection별 evdev event

333-413

Linux는 각 Application Collection마다 `/dev/input/event*` 하나를 만듭니다.

Mouse 예에서 `libinput record /dev/input/event1`을 실행하면 device metadata, 지원 event type·code, HID descriptor, udev property와 실제 evdev event sequence를 기록합니다.

예제 device는 `EV_SYN`, `EV_KEY`, `EV_REL`, `EV_MSC`를 지원합니다. Key code는 `BTN_LEFT`, `BTN_RIGHT`, `BTN_MIDDLE`, relative code는 `REL_X`, `REL_Y`, `REL_WHEEL`, `REL_WHEEL_HI_RES`, scan code는 `MSC_SCAN`입니다.

기록된 sequence는 left press, right press, left release, right release입니다. 각 변화에는 `MSC_SCAN`, 해당 `EV_KEY` 값 1 또는 0과 `SYN_REPORT`가 함께 기록됩니다.

Device는 `ID_INPUT=1`, `ID_INPUT_MOUSE=1` udev property를 가지며 예제의 device name은 `PixArt HP USB Optical Mouse`입니다.

System에 `libinput record`가 없으면 `evemu-record`를 사용할 수 있습니다.

Mouse evdev capability
Event typeCodes
EV_KEYBTN_LEFT · BTN_RIGHT · BTN_MIDDLE
EV_RELREL_X · REL_Y · REL_WHEEL · REL_WHEEL_HI_RES
EV_MSCMSC_SCAN
EV_SYNSYN_REPORT

Descriptor에서 생성된 주요 event code입니다.

Evdev record sequence
Application Collection에 event node 생성Raw Input Report에서 usage change 해석MSC_SCAN과 EV_KEY event 생성Press는 value 1, release는 value 0SYN_REPORT로 event frame 종료libinput record 또는 evemu-record로 확인

Button report가 userspace event frame으로 바뀝니다.


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``.

오동작 원인과 HID quirk

414-457

Device가 올바르게 동작하지 않는 데는 여러 이유가 있습니다.

Device가 제공한 descriptor가 표준을 따르지 않아 kernel이 의미를 해석하지 못할 수 있습니다. 또는 descriptor가 device가 실제로 보내는 data와 일치하지 않을 수 있으며, raw HID data를 읽어 이를 검증할 수 있습니다. Descriptor에 특정 quirk가 필요할 수도 있습니다.

그 결과 각 Application Collection에 `/dev/input/event*`가 만들어지지 않거나 event가 예상과 다를 수 있습니다.

Kernel이 수정 방법을 알고 있는 HID device의 알려진 특이점을 HID quirk라 부르며 목록은 `include/linux/hid.h`에 있습니다.

해당하는 quirk가 있다면 대상 HID device를 위해 kernel에 quirk를 추가하면 됩니다. 위치는 `drivers/hid/hid-quirks.c`이며 file의 기존 항목을 보면 방법을 파악할 수 있습니다.

현재 정의된 quirk 목록은 `include/linux/hid.h`의 kernel-doc에서 문서에 포함됩니다.

USB device quirk는 `modinfo usbhid`에 나온 module load parameter로 지정할 수도 있습니다. 그러나 올바른 수정은 `hid-quirks.c`에 넣고 upstream에 제출해야 합니다.

Patch 제출 지침은 `Documentation/process/submitting-patches.rst`에 있습니다. 다른 bus의 quirk는 반드시 `hid-quirks.c`에 들어가야 합니다.

HID 오동작 진단
원인확인·수정
Descriptor가 표준 위반Parser output과 HID Spec 비교
Descriptor와 실제 report 불일치Raw HID data 기록
알려진 device peculiarityinclude/linux/hid.h quirk 확인
Event node 누락·mapping 오류Application Collection과 evdev 비교

증상과 확인 지점을 연결합니다.

Quirk 수정
Descriptor·raw report·evdev 증상 수집기존 HID quirk 목록 확인drivers/hid/hid-quirks.c에 device quirk 추가USB는 module parameter로 임시 검증 가능Kernel build·device 동작 재검증Submitting-patches 지침에 따라 upstream 제출

Local 확인에서 upstream 반영까지의 경로입니다.

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.

HID-BPF 또는 kernel에서 descriptor 수정

458-490

HID report descriptor를 patch해야 한다면 가장 쉬운 방법은 `Documentation/hid/hid-bpf.rst`에 설명된 eBPF를 사용하는 것입니다.

원본 descriptor의 어떤 byte든 바꿀 수 있습니다. `samples/hid` 예제가 시작점이며 `samples/hid/hid_mouse.bpf.c`는 `fmod_ret/hid_bpf_rdesc_fixup` program에서 특정 byte를 교체합니다.

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;
}

Kernel source에서 직접 수정할 수도 있습니다. 간단한 예는 `drivers/hid/hid-aureal.c`, 조금 더 복잡한 예는 `drivers/hid/hid-samsung.c`입니다.

HID manual 탐색과 descriptor hex number의 정확한 의미에 도움이 필요하면 `Documentation/hid/hidreport-parsing.rst`를 확인합니다.

어떤 해결책을 만들든 HID maintainer에게 fix를 제출해야 합니다. 그래야 kernel에 직접 통합되어 같은 HID device가 다른 사용자에게도 동작합니다. 제출 방법은 `Documentation/process/submitting-patches.rst`를 따릅니다.

Descriptor 수정 선택지
방법위치·예
HID-BPFsamples/hid/hid_mouse.bpf.c
Kernel HID driverdrivers/hid/hid-aureal.c
복잡한 kernel fixdrivers/hid/hid-samsung.c
Parsing 참고Documentation/hid/hidreport-parsing.rst

검증·배포 범위에 따른 방법입니다.

Descriptor fix 개발
Raw descriptor와 실제 report 비교수정할 item·byte offset 식별HID-BPF fixup으로 빠르게 검증필요하면 kernel driver fix 작성Event mapping과 device 기능 재검사HID maintainer에게 upstream 제출

잘못된 byte를 수정하고 공유하는 과정입니다.

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.

전송 data 수정과 specialized driver

491-506

eBPF를 사용하면 device와 교환하는 data도 실행 중에 수정할 수 있습니다. 관련 예제는 다시 `samples/hid`에서 확인합니다.

이 수정도 kernel에 통합될 수 있도록 반드시 게시하고 제출해야 합니다.

Specialized driver 작성은 정말 마지막 수단이어야 합니다.

문제 해결 우선순위
순서방법
1기존 quirk 적용·추가
2HID-BPF descriptor fixup
3HID-BPF로 exchanged data 수정
4기존 HID driver의 scoped fix
5Specialized driver 작성

유지보수 범위가 작은 방법부터 적용합니다.

최소 수정 원칙
Default HID path로 해결 가능한지 확인Quirk 또는 descriptor fix 검토Data transform으로 해결 가능한지 검증마지막에만 specialized driver 선택재현 자료와 fix를 upstream 제출

필요한 범위만 확장하고 upstream으로 공유합니다.


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.

Hidraw descriptor read 예제

507-524

Hidraw 사용법은 `Documentation/hid/hidraw.rst`와 예제 `samples/hidraw/hid-example.c`를 참조합니다.

같은 mouse에서 `hid-example`을 실행하면 report descriptor size `52`, 전체 descriptor byte, raw name과 physical path, USB bus type, vendor `0x093a`, product `0x2510`을 출력합니다.

$ sudo ./hid-example
Report Descriptor Size: 52
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
hid-example metadata
항목
Descriptor size52 bytes
Raw namePixArt USB Optical Mouse
Raw physical pathusb-0000:05:00.4-2.3/input0
Bus type3 (USB)
Vendor / product0x093a / 0x2510

Footnote 예제에서 확인하는 값입니다.

Hidraw 직접 조사
대상 hidraw node 선택samples/hidraw/hid-example.c buildhid-example 실행Descriptor size와 byte 확인Raw name·phys·USB ID를 device와 대조

Kernel input mapping 전의 raw 정보를 확인합니다.

.. 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
    ...