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

Linux 6.18.37 · HID

UHID - User-space I/O driver support for HID subsystem

Userspace HID transport가 /dev/uhid event protocol로 virtual HID device를 생성하고 report를 교환하는 방법입니다.

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

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

1. 요약·해설

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

요약·해설

uhid.rst:1-193

UHID는 userspace transport driver가 `/dev/uhid`에 `struct uhid_event`를 읽고 써서 kernel HID device를 만들고 관리하는 interface입니다.

Device lifecycle, interrupt-channel input/output, numbered-report prefix와 synchronous GET_REPORT·SET_REPORT reply가 핵심 contract입니다.

문서 범위
항목
SourceDocumentation/hid/uhid.rst
분량193 source lines
Device node/dev/uhid
I/O objectstruct uhid_event
Examplesamples/uhid/uhid-example.c

UHID userspace API의 주요 요소입니다.

UHID transport
/dev/uhid openUHID_CREATE2로 device 생성UHID_START와 OPEN 상태 확인UHID_INPUT2·OUTPUT으로 interrupt data 교환GET_REPORT·SET_REPORT를 synchronous reply로 처리UHID_DESTROY 또는 fd close로 제거

Virtual device의 대표적인 실행 흐름입니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 ======================================================
2 UHID - User-space I/O driver support for HID subsystem
3 ======================================================
4
5 UHID allows user-space to implement HID transport drivers. Please see
6 hid-transport.rst for an introduction into HID transport drivers. This document
7 relies heavily on the definitions declared there.
8
9 With UHID, a user-space transport driver can create kernel hid-devices for each
10 device connected to the user-space controlled bus. The UHID API defines the I/O
11 events provided from the kernel to user-space and vice versa.
12
13 There is an example user-space application in ./samples/uhid/uhid-example.c
14
15 The UHID API
16 ------------
17
18 UHID is accessed through a character misc-device. The minor number is allocated
19 dynamically so you need to rely on udev (or similar) to create the device node.
20 This is /dev/uhid by default.
21
22 If a new device is detected by your HID I/O Driver and you want to register this
23 device with the HID subsystem, then you need to open /dev/uhid once for each
24 device you want to register. All further communication is done by read()'ing or
25 write()'ing "struct uhid_event" objects. Non-blocking operations are supported
26 by setting O_NONBLOCK::
27
28 struct uhid_event {
29 __u32 type;
30 union {
31 struct uhid_create2_req create2;
32 struct uhid_output_req output;
33 struct uhid_input2_req input2;
34 ...
35 } u;
36 };
37
38 The "type" field contains the ID of the event. Depending on the ID different
39 payloads are sent. You must not split a single event across multiple read()'s or
40 multiple write()'s. A single event must always be sent as a whole. Furthermore,
41 only a single event can be sent per read() or write(). Pending data is ignored.
42 If you want to handle multiple events in a single syscall, then use vectored
43 I/O with readv()/writev().
44 The "type" field defines the payload. For each type, there is a
45 payload-structure available in the union "u" (except for empty payloads). This
46 payload contains management and/or device data.
47
48 The first thing you should do is send a UHID_CREATE2 event. This will
49 register the device. UHID will respond with a UHID_START event. You can now
50 start sending data to and reading data from UHID. However, unless UHID sends the
51 UHID_OPEN event, the internally attached HID Device Driver has no user attached.
52 That is, you might put your device asleep unless you receive the UHID_OPEN
53 event. If you receive the UHID_OPEN event, you should start I/O. If the last
54 user closes the HID device, you will receive a UHID_CLOSE event. This may be
55 followed by a UHID_OPEN event again and so on. There is no need to perform
56 reference-counting in user-space. That is, you will never receive multiple
57 UHID_OPEN events without a UHID_CLOSE event. The HID subsystem performs
58 ref-counting for you.
59 You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
60 though the device may have no users.
61
62 If you want to send data on the interrupt channel to the HID subsystem, you send
63 a HID_INPUT2 event with your raw data payload. If the kernel wants to send data
64 on the interrupt channel to the device, you will read a UHID_OUTPUT event.
65 Data requests on the control channel are currently limited to GET_REPORT and
66 SET_REPORT (no other data reports on the control channel are defined so far).
67 Those requests are always synchronous. That means, the kernel sends
68 UHID_GET_REPORT and UHID_SET_REPORT events and requires you to forward them to
69 the device on the control channel. Once the device responds, you must forward
70 the response via UHID_GET_REPORT_REPLY and UHID_SET_REPORT_REPLY to the kernel.
71 The kernel blocks internal driver-execution during such round-trips (times out
72 after a hard-coded period).
73
74 If your device disconnects, you should send a UHID_DESTROY event. This will
75 unregister the device. You can now send UHID_CREATE2 again to register a new
76 device.
77 If you close() the fd, the device is automatically unregistered and destroyed
78 internally.
79
80 write()
81 -------
82 write() allows you to modify the state of the device and feed input data into
83 the kernel. The kernel will parse the event immediately and if the event ID is
84 not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
85 -EINVAL is returned, otherwise, the amount of data that was read is returned and
86 the request was handled successfully. O_NONBLOCK does not affect write() as
87 writes are always handled immediately in a non-blocking fashion. Future requests
88 might make use of O_NONBLOCK, though.
89
90 UHID_CREATE2:
91 This creates the internal HID device. No I/O is possible until you send this
92 event to the kernel. The payload is of type struct uhid_create2_req and
93 contains information about your device. You can start I/O now.
94
95 UHID_DESTROY:
96 This destroys the internal HID device. No further I/O will be accepted. There
97 may still be pending messages that you can receive with read() but no further
98 UHID_INPUT events can be sent to the kernel.
99 You can create a new device by sending UHID_CREATE2 again. There is no need to
100 reopen the character device.
101
102 UHID_INPUT2:
103 You must send UHID_CREATE2 before sending input to the kernel! This event
104 contains a data-payload. This is the raw data that you read from your device
105 on the interrupt channel. The kernel will parse the HID reports.
106
107 UHID_GET_REPORT_REPLY:
108 If you receive a UHID_GET_REPORT request you must answer with this request.
109 You must copy the "id" field from the request into the answer. Set the "err"
110 field to 0 if no error occurred or to EIO if an I/O error occurred.
111 If "err" is 0 then you should fill the buffer of the answer with the results
112 of the GET_REPORT request and set "size" correspondingly.
113
114 UHID_SET_REPORT_REPLY:
115 This is the SET_REPORT equivalent of UHID_GET_REPORT_REPLY. Unlike GET_REPORT,
116 SET_REPORT never returns a data buffer, therefore, it's sufficient to set the
117 "id" and "err" fields correctly.
118
119 read()
120 ------
121 read() will return a queued output report. No reaction is required to any of
122 them but you should handle them according to your needs.
123
124 UHID_START:
125 This is sent when the HID device is started. Consider this as an answer to
126 UHID_CREATE2. This is always the first event that is sent. Note that this
127 event might not be available immediately after write(UHID_CREATE2) returns.
128 Device drivers might require delayed setups.
129 This event contains a payload of type uhid_start_req. The "dev_flags" field
130 describes special behaviors of a device. The following flags are defined:
131
132 - UHID_DEV_NUMBERED_FEATURE_REPORTS
133 - UHID_DEV_NUMBERED_OUTPUT_REPORTS
134 - UHID_DEV_NUMBERED_INPUT_REPORTS
135
136 Each of these flags defines whether a given report-type uses numbered
137 reports. If numbered reports are used for a type, all messages from
138 the kernel already have the report-number as prefix. Otherwise, no
139 prefix is added by the kernel.
140 For messages sent by user-space to the kernel, you must adjust the
141 prefixes according to these flags.
142
143 UHID_STOP:
144 This is sent when the HID device is stopped. Consider this as an answer to
145 UHID_DESTROY.
146
147 If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
148 UHID_STOP event, this should usually be ignored. It means that the kernel
149 reloaded/changed the device driver loaded on your HID device (or some other
150 maintenance actions happened).
151
152 You can usually ignore any UHID_STOP events safely.
153
154 UHID_OPEN:
155 This is sent when the HID device is opened. That is, the data that the HID
156 device provides is read by some other process. You may ignore this event but
157 it is useful for power-management. As long as you haven't received this event
158 there is actually no other process that reads your data so there is no need to
159 send UHID_INPUT2 events to the kernel.
160
161 UHID_CLOSE:
162 This is sent when there are no more processes which read the HID data. It is
163 the counterpart of UHID_OPEN and you may as well ignore this event.
164
165 UHID_OUTPUT:
166 This is sent if the HID device driver wants to send raw data to the I/O
167 device on the interrupt channel. You should read the payload and forward it to
168 the device. The payload is of type "struct uhid_output_req".
169 This may be received even though you haven't received UHID_OPEN yet.
170
171 UHID_GET_REPORT:
172 This event is sent if the kernel driver wants to perform a GET_REPORT request
173 on the control channel as described in the HID specs. The report-type and
174 report-number are available in the payload.
175 The kernel serializes GET_REPORT requests so there will never be two in
176 parallel. However, if you fail to respond with a UHID_GET_REPORT_REPLY, the
177 request might silently time out.
178 Once you read a GET_REPORT request, you shall forward it to the HID device and
179 remember the "id" field in the payload. Once your HID device responds to the
180 GET_REPORT (or if it fails), you must send a UHID_GET_REPORT_REPLY to the
181 kernel with the exact same "id" as in the request. If the request already
182 timed out, the kernel will ignore the response silently. The "id" field is
183 never re-used, so conflicts cannot happen.
184
185 UHID_SET_REPORT:
186 This is the SET_REPORT equivalent of UHID_GET_REPORT. On receipt, you shall
187 send a SET_REPORT request to your HID device. Once it replies, you must tell
188 the kernel about it via UHID_SET_REPORT_REPLY.
189 The same restrictions as for UHID_GET_REPORT apply.
190
191 ----------------------------------------------------
192
193 Written 2012, David Herrmann <dh.herrmann@gmail.com>
194

3. 한국어 전문 번역

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

Userspace HID transport와 event framing

1-47

UHID는 userspace에서 HID transport driver를 구현할 수 있게 합니다. HID transport driver의 기본 개념은 `hid-transport.rst`를 참조하며, 이 문서는 그 문서의 정의를 전제로 합니다.

Userspace가 제어하는 bus에 연결된 device마다 userspace transport driver가 kernel hid-device를 만들 수 있습니다. UHID API는 kernel에서 userspace로, userspace에서 kernel로 전달되는 I/O event를 정의합니다. 예제 application은 `./samples/uhid/uhid-example.c`에 있습니다.

UHID는 character misc-device로 접근합니다. Minor number는 동적으로 할당되므로 udev 같은 도구가 device node를 만들어야 하며 기본 node는 `/dev/uhid`입니다.

HID I/O driver가 새 device를 발견하여 HID subsystem에 등록하려면 device마다 `/dev/uhid`를 한 번씩 open해야 합니다. 이후 모든 통신은 `struct uhid_event` object를 `read()`하거나 `write()`하는 방식입니다. `O_NONBLOCK`으로 non-blocking operation도 사용할 수 있습니다.

`struct uhid_event`에는 event ID인 `__u32 type`과 payload union `u`가 있습니다. Union에는 `struct uhid_create2_req create2`, `struct uhid_output_req output`, `struct uhid_input2_req input2` 등이 들어갑니다. Payload가 없는 event를 제외하면 type마다 union 안의 대응 payload structure가 있으며 management 또는 device data를 담습니다.

Event 하나를 여러 `read()` 또는 여러 `write()`로 나누면 안 됩니다. Event는 언제나 한 번에 전체를 보내야 하며 read/write 호출 하나에도 event 하나만 담을 수 있습니다. 뒤따르는 data는 무시됩니다. 한 syscall에서 여러 event를 처리하려면 `readv()` 또는 `writev()`의 vectored I/O를 사용합니다.

struct uhid_event
FieldType·예역할
type__u32UHID event ID
u.create2struct uhid_create2_reqVirtual HID device 생성 정보
u.outputstruct uhid_output_reqKernel의 interrupt-channel output
u.input2struct uhid_input2_reqUserspace의 raw input report
u의 기타 memberEvent별 structureManagement 또는 device data

Event ID가 union payload의 해석을 결정합니다.

UHID event 전송 단위
udev가 /dev/uhid node 생성등록할 device마다 fd 하나 openEvent type과 대응 union payload 구성Event 전체를 read() 또는 write() 한 번으로 전달여러 event는 readv()/writev() vector element로 분리

하나의 event는 하나의 완전한 I/O object입니다.

======================================================
UHID - User-space I/O driver support for HID subsystem
======================================================

UHID allows user-space to implement HID transport drivers. Please see
hid-transport.rst for an introduction into HID transport drivers. This document
relies heavily on the definitions declared there.

With UHID, a user-space transport driver can create kernel hid-devices for each
device connected to the user-space controlled bus. The UHID API defines the I/O
events provided from the kernel to user-space and vice versa.

There is an example user-space application in ./samples/uhid/uhid-example.c

The UHID API
------------

UHID is accessed through a character misc-device. The minor number is allocated
dynamically so you need to rely on udev (or similar) to create the device node.
This is /dev/uhid by default.

If a new device is detected by your HID I/O Driver and you want to register this
device with the HID subsystem, then you need to open /dev/uhid once for each
device you want to register. All further communication is done by read()'ing or
write()'ing "struct uhid_event" objects. Non-blocking operations are supported
by setting O_NONBLOCK::

  struct uhid_event {
        __u32 type;
        union {
                struct uhid_create2_req create2;
                struct uhid_output_req output;
                struct uhid_input2_req input2;
                ...
        } u;
  };

The "type" field contains the ID of the event. Depending on the ID different
payloads are sent. You must not split a single event across multiple read()'s or
multiple write()'s. A single event must always be sent as a whole. Furthermore,
only a single event can be sent per read() or write(). Pending data is ignored.
If you want to handle multiple events in a single syscall, then use vectored
I/O with readv()/writev().
The "type" field defines the payload. For each type, there is a
payload-structure available in the union "u" (except for empty payloads). This
payload contains management and/or device data.

Device lifecycle과 data channel

48-79

가장 먼저 `UHID_CREATE2` event를 보내 device를 등록해야 합니다. UHID는 `UHID_START`로 응답하며 그 뒤부터 data를 보내고 읽을 수 있습니다.

다만 UHID가 `UHID_OPEN`을 보내기 전에는 내부에 attach된 HID Device Driver를 사용하는 process가 없습니다. OPEN을 받지 않았다면 device를 sleep 상태로 둘 수 있고, OPEN을 받으면 I/O를 시작해야 합니다. 마지막 user가 HID device를 닫으면 `UHID_CLOSE`가 오며 이후 다시 OPEN이 올 수 있습니다.

Userspace에서 reference count를 직접 관리할 필요는 없습니다. HID subsystem이 대신 처리하므로 CLOSE 없이 OPEN이 여러 번 연속 전달되는 일은 없습니다. OPEN/CLOSE를 무시해도 되며 실제 user가 없는 상태에서도 I/O는 허용됩니다.

Interrupt channel로 HID subsystem에 data를 보낼 때는 raw payload를 넣은 `HID_INPUT2` event를 보냅니다. Kernel이 interrupt channel로 device에 data를 보낼 때 userspace는 `UHID_OUTPUT` event를 읽습니다.

Control channel data request는 현재 `GET_REPORT`와 `SET_REPORT`만 정의되어 있으며 항상 synchronous입니다. Kernel의 `UHID_GET_REPORT` 또는 `UHID_SET_REPORT`를 device control channel로 전달하고, device 응답을 각각 `UHID_GET_REPORT_REPLY`, `UHID_SET_REPORT_REPLY`로 kernel에 되돌려야 합니다. 이 round trip 동안 kernel은 internal driver execution을 block하며 hard-coded 시간이 지나면 timeout됩니다.

Device가 disconnect되면 `UHID_DESTROY`를 보내 등록을 해제합니다. 이후 같은 fd에서 `UHID_CREATE2`를 다시 보내 새 device를 등록할 수 있습니다. fd를 `close()`하면 device는 내부적으로 자동 unregister되고 destroy됩니다.

UHID lifecycle event
Event방향의미
UHID_CREATE2Userspace → KernelInternal HID device 생성
UHID_STARTKernel → Userspace생성 뒤 HID device 시작
UHID_OPEN / UHID_CLOSEKernel → Userspace첫 user open / 마지막 user close
UHID_DESTROYUserspace → KernelDevice unregister·destroy
fd close()UserspaceDevice 자동 unregister·destroy

등록, 사용 여부, 해제의 방향을 정리했습니다.

Device 수명주기
/dev/uhid openUHID_CREATE2로 device 등록UHID_START 뒤 OPEN에 맞춰 I/O 시작OPEN과 CLOSE를 따라 power state 조정Disconnect 시 UHID_DESTROY 전송필요하면 같은 fd에서 UHID_CREATE2 재전송 또는 fd close

하나의 fd에서 device를 없애고 다시 만들 수도 있습니다.

The first thing you should do is send a UHID_CREATE2 event. This will
register the device. UHID will respond with a UHID_START event. You can now
start sending data to and reading data from UHID. However, unless UHID sends the
UHID_OPEN event, the internally attached HID Device Driver has no user attached.
That is, you might put your device asleep unless you receive the UHID_OPEN
event. If you receive the UHID_OPEN event, you should start I/O. If the last
user closes the HID device, you will receive a UHID_CLOSE event. This may be
followed by a UHID_OPEN event again and so on. There is no need to perform
reference-counting in user-space. That is, you will never receive multiple
UHID_OPEN events without a UHID_CLOSE event. The HID subsystem performs
ref-counting for you.
You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
though the device may have no users.

If you want to send data on the interrupt channel to the HID subsystem, you send
a HID_INPUT2 event with your raw data payload. If the kernel wants to send data
on the interrupt channel to the device, you will read a UHID_OUTPUT event.
Data requests on the control channel are currently limited to GET_REPORT and
SET_REPORT (no other data reports on the control channel are defined so far).
Those requests are always synchronous. That means, the kernel sends
UHID_GET_REPORT and UHID_SET_REPORT events and requires you to forward them to
the device on the control channel. Once the device responds, you must forward
the response via UHID_GET_REPORT_REPLY and UHID_SET_REPORT_REPLY to the kernel.
The kernel blocks internal driver-execution during such round-trips (times out
after a hard-coded period).

If your device disconnects, you should send a UHID_DESTROY event. This will
unregister the device. You can now send UHID_CREATE2 again to register a new
device.
If you close() the fd, the device is automatically unregistered and destroyed
internally.

write()와 userspace 발신 event

80-118

`write()`는 device state를 변경하고 input data를 kernel에 공급합니다. Kernel은 event를 즉시 parse합니다. 지원하지 않는 event ID이면 `-EOPNOTSUPP`, payload가 유효하지 않으면 `-EINVAL`을 반환합니다. 성공하면 읽어 처리한 data 양을 반환합니다.

Write는 언제나 즉시 non-blocking 방식으로 처리되므로 현재 `O_NONBLOCK`의 영향을 받지 않습니다. 다만 향후 request에서 이 flag를 사용할 가능성은 있습니다.

`UHID_CREATE2`는 internal HID device를 만듭니다. 이 event를 kernel에 보내기 전에는 I/O를 할 수 없습니다. Payload는 `struct uhid_create2_req`이며 device 정보를 담습니다. 생성 뒤 I/O를 시작할 수 있습니다.

`UHID_DESTROY`는 internal HID device를 없애고 이후 I/O를 받지 않습니다. `read()`로 받을 pending message가 남을 수 있지만 kernel로 더 이상 `UHID_INPUT` event를 보낼 수 없습니다. Character device를 다시 open하지 않고 `UHID_CREATE2`로 새 device를 만들 수 있습니다.

`UHID_INPUT2`를 보내기 전에 반드시 `UHID_CREATE2`를 보내야 합니다. INPUT2 payload는 실제 device의 interrupt channel에서 읽은 raw data이며 kernel이 HID report를 parse합니다.

`UHID_GET_REPORT` request를 받으면 `UHID_GET_REPORT_REPLY`로 답해야 합니다. Request의 `id`를 reply에 그대로 복사합니다. Error가 없으면 `err = 0`, I/O error이면 `err = EIO`로 설정합니다. `err`가 0이면 GET_REPORT 결과를 reply buffer에 채우고 `size`도 맞춰야 합니다.

`UHID_SET_REPORT_REPLY`는 GET_REPORT reply에 대응하는 SET_REPORT 응답입니다. SET_REPORT는 data buffer를 반환하지 않으므로 `id`와 `err` field만 올바르게 설정하면 됩니다.

write() event와 결과
EventPayload·field효과
UHID_CREATE2struct uhid_create2_reqInternal HID device 생성
UHID_DESTROYEmpty payload추가 I/O 차단·device 제거
UHID_INPUT2Raw interrupt-channel dataKernel HID report parser에 입력
UHID_GET_REPORT_REPLYid · err · size · bufferSynchronous GET_REPORT 완료
UHID_SET_REPORT_REPLYid · errSynchronous SET_REPORT 완료

Userspace가 kernel에 보내는 주요 event입니다.

GET_REPORT reply 작성
Kernel에서 UHID_GET_REPORT request 수신Request id를 저장하고 physical device에 전달Device response 또는 I/O failure 확인성공이면 err=0, size와 buffer 채우기실패이면 err=EIO 설정동일 id의 UHID_GET_REPORT_REPLY를 write()

Request와 같은 id를 보존해야 합니다.

write()
-------
write() allows you to modify the state of the device and feed input data into
the kernel. The kernel will parse the event immediately and if the event ID is
not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
-EINVAL is returned, otherwise, the amount of data that was read is returned and
the request was handled successfully. O_NONBLOCK does not affect write() as
writes are always handled immediately in a non-blocking fashion. Future requests
might make use of O_NONBLOCK, though.

UHID_CREATE2:
  This creates the internal HID device. No I/O is possible until you send this
  event to the kernel. The payload is of type struct uhid_create2_req and
  contains information about your device. You can start I/O now.

UHID_DESTROY:
  This destroys the internal HID device. No further I/O will be accepted. There
  may still be pending messages that you can receive with read() but no further
  UHID_INPUT events can be sent to the kernel.
  You can create a new device by sending UHID_CREATE2 again. There is no need to
  reopen the character device.

UHID_INPUT2:
  You must send UHID_CREATE2 before sending input to the kernel! This event
  contains a data-payload. This is the raw data that you read from your device
  on the interrupt channel. The kernel will parse the HID reports.

UHID_GET_REPORT_REPLY:
  If you receive a UHID_GET_REPORT request you must answer with this request.
  You  must copy the "id" field from the request into the answer. Set the "err"
  field to 0 if no error occurred or to EIO if an I/O error occurred.
  If "err" is 0 then you should fill the buffer of the answer with the results
  of the GET_REPORT request and set "size" correspondingly.

UHID_SET_REPORT_REPLY:
  This is the SET_REPORT equivalent of UHID_GET_REPORT_REPLY. Unlike GET_REPORT,
  SET_REPORT never returns a data buffer, therefore, it's sufficient to set the
  "id" and "err" fields correctly.

read()와 kernel 발신 event

119-170

`read()`는 queue된 output report를 반환합니다. 어떤 event에도 반드시 반응해야 하는 것은 아니지만 application 요구에 맞게 처리하는 것이 좋습니다.

`UHID_START`는 HID device가 시작될 때 전달되며 `UHID_CREATE2`의 응답으로 볼 수 있습니다. 언제나 kernel이 보내는 첫 event이지만 `write(UHID_CREATE2)`가 반환된 직후 곧바로 준비되지는 않을 수 있습니다. Device driver가 지연된 setup을 요구할 수 있기 때문입니다.

START payload는 `uhid_start_req`이며 `dev_flags`가 device의 특별한 동작을 설명합니다. 정의된 flag는 `UHID_DEV_NUMBERED_FEATURE_REPORTS`, `UHID_DEV_NUMBERED_OUTPUT_REPORTS`, `UHID_DEV_NUMBERED_INPUT_REPORTS`입니다.

각 flag는 해당 report type이 numbered report를 쓰는지를 나타냅니다. Numbered report라면 kernel이 보내는 모든 message에 report number prefix가 이미 붙습니다. 그렇지 않으면 kernel이 prefix를 붙이지 않습니다. Userspace에서 kernel로 보내는 message도 이 flag에 맞춰 prefix를 조정해야 합니다.

`UHID_STOP`은 HID device가 정지될 때 전달되며 `UHID_DESTROY`의 응답으로 볼 수 있습니다. Userspace가 DESTROY하지 않았는데 kernel이 STOP을 보냈다면 보통 kernel이 HID device driver를 reload·change했거나 maintenance action을 수행했다는 뜻이므로 무시해도 됩니다. 일반적으로 모든 STOP event는 안전하게 무시할 수 있습니다.

`UHID_OPEN`은 다른 process가 HID device의 data를 읽기 시작해 device가 open될 때 전달됩니다. 무시할 수도 있지만 power management에 유용합니다. OPEN 전에는 data를 읽는 process가 없으므로 kernel에 `UHID_INPUT2`를 보낼 필요가 없습니다.

`UHID_CLOSE`는 HID data를 읽는 process가 더 이상 없을 때 전달되는 OPEN의 반대 event이며 역시 무시할 수 있습니다.

`UHID_OUTPUT`은 HID device driver가 interrupt channel로 I/O device에 raw data를 보내려 할 때 전달됩니다. `struct uhid_output_req` payload를 읽어 device에 전달해야 합니다. 이 event는 아직 `UHID_OPEN`을 받지 않은 상태에서도 올 수 있습니다.

read() event
Event시점권장 처리
UHID_STARTHID device 시작첫 event로 받고 dev_flags 확인
UHID_STOPDevice stop·driver maintenance대개 안전하게 무시
UHID_OPEN첫 data reader openI/O 시작·device wake
UHID_CLOSE마지막 reader closeI/O 중지·device sleep 가능
UHID_OUTPUTKernel interrupt-channel outputstruct uhid_output_req를 device로 전달

Kernel이 userspace transport에 알리는 상태와 output입니다.

Numbered report prefix 결정
UHID_START의 uhid_start_req 수신Feature·Output·Input numbered flag 확인Kernel 발신 message의 기존 report-number prefix 인식Flag가 없으면 prefix 없는 payload로 처리Userspace 발신 message도 같은 규칙으로 prefix 조정

START의 dev_flags가 각 report type의 framing을 정합니다.

read()
------
read() will return a queued output report. No reaction is required to any of
them but you should handle them according to your needs.

UHID_START:
  This is sent when the HID device is started. Consider this as an answer to
  UHID_CREATE2. This is always the first event that is sent. Note that this
  event might not be available immediately after write(UHID_CREATE2) returns.
  Device drivers might require delayed setups.
  This event contains a payload of type uhid_start_req. The "dev_flags" field
  describes special behaviors of a device. The following flags are defined:

      - UHID_DEV_NUMBERED_FEATURE_REPORTS
      - UHID_DEV_NUMBERED_OUTPUT_REPORTS
      - UHID_DEV_NUMBERED_INPUT_REPORTS

          Each of these flags defines whether a given report-type uses numbered
          reports. If numbered reports are used for a type, all messages from
          the kernel already have the report-number as prefix. Otherwise, no
          prefix is added by the kernel.
          For messages sent by user-space to the kernel, you must adjust the
          prefixes according to these flags.

UHID_STOP:
  This is sent when the HID device is stopped. Consider this as an answer to
  UHID_DESTROY.

  If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
  UHID_STOP event, this should usually be ignored. It means that the kernel
  reloaded/changed the device driver loaded on your HID device (or some other
  maintenance actions happened).

  You can usually ignore any UHID_STOP events safely.

UHID_OPEN:
  This is sent when the HID device is opened. That is, the data that the HID
  device provides is read by some other process. You may ignore this event but
  it is useful for power-management. As long as you haven't received this event
  there is actually no other process that reads your data so there is no need to
  send UHID_INPUT2 events to the kernel.

UHID_CLOSE:
  This is sent when there are no more processes which read the HID data. It is
  the counterpart of UHID_OPEN and you may as well ignore this event.

UHID_OUTPUT:
  This is sent if the HID device driver wants to send raw data to the I/O
  device on the interrupt channel. You should read the payload and forward it to
  the device. The payload is of type "struct uhid_output_req".
  This may be received even though you haven't received UHID_OPEN yet.

Synchronous GET_REPORT·SET_REPORT

171-193

`UHID_GET_REPORT`는 HID specification의 control channel에서 kernel driver가 GET_REPORT를 수행하려 할 때 전달됩니다. Payload에서 report type과 report number를 확인할 수 있습니다.

Kernel은 GET_REPORT를 serialize하므로 두 request가 동시에 진행되지 않습니다. 하지만 `UHID_GET_REPORT_REPLY`로 응답하지 않으면 request가 조용히 timeout될 수 있습니다.

GET_REPORT를 읽으면 physical HID device로 전달하고 payload의 `id`를 기억해야 합니다. Device가 응답하거나 실패하면 request와 정확히 같은 `id`로 `UHID_GET_REPORT_REPLY`를 kernel에 보냅니다. 이미 timeout된 request의 response는 kernel이 조용히 무시합니다. `id`는 재사용되지 않으므로 conflict가 발생하지 않습니다.

`UHID_SET_REPORT`는 GET_REPORT와 같은 방식의 SET_REPORT request입니다. 수신하면 HID device에 SET_REPORT를 보내고 device reply를 `UHID_SET_REPORT_REPLY`로 kernel에 알려야 합니다. GET_REPORT와 동일한 제한이 적용됩니다.

이 문서는 David Herrmann이 2012년에 작성했습니다.

Control-channel round trip
RequestDevice 전달Kernel reply
UHID_GET_REPORTGET_REPORT + report type·numberUHID_GET_REPORT_REPLY: 같은 id, err, 선택적 data
UHID_SET_REPORTSET_REPORTUHID_SET_REPORT_REPLY: 같은 id와 err
TimeoutDevice response가 늦음Kernel이 늦은 reply를 조용히 무시
SerializationGET_REPORT 한 번에 하나id는 재사용하지 않음

GET과 SET은 모두 synchronous이며 request id로 대응됩니다.

Synchronous control request
Kernel에서 GET_REPORT 또는 SET_REPORT event readPayload의 id와 report metadata 저장Physical HID device control channel로 request 전달Device response 또는 failure 대기같은 id로 대응 REPLY event writeTimeout이 이미 발생했으면 kernel이 reply 무시

Kernel execution은 reply 또는 timeout까지 block됩니다.

UHID_GET_REPORT:
  This event is sent if the kernel driver wants to perform a GET_REPORT request
  on the control channel as described in the HID specs. The report-type and
  report-number are available in the payload.
  The kernel serializes GET_REPORT requests so there will never be two in
  parallel. However, if you fail to respond with a UHID_GET_REPORT_REPLY, the
  request might silently time out.
  Once you read a GET_REPORT request, you shall forward it to the HID device and
  remember the "id" field in the payload. Once your HID device responds to the
  GET_REPORT (or if it fails), you must send a UHID_GET_REPORT_REPLY to the
  kernel with the exact same "id" as in the request. If the request already
  timed out, the kernel will ignore the response silently. The "id" field is
  never re-used, so conflicts cannot happen.

UHID_SET_REPORT:
  This is the SET_REPORT equivalent of UHID_GET_REPORT. On receipt, you shall
  send a SET_REPORT request to your HID device. Once it replies, you must tell
  the kernel about it via UHID_SET_REPORT_REPLY.
  The same restrictions as for UHID_GET_REPORT apply.

----------------------------------------------------

Written 2012, David Herrmann <dh.herrmann@gmail.com>