요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
======================================================
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.
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()
-------
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()
------
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.
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 <[email protected]>
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Userspace HID transport와 event framing
1-47UHID는 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를 사용합니다.
Event ID가 union payload의 해석을 결정합니다.
하나의 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됩니다.
등록, 사용 여부, 해제의 방향을 정리했습니다.
하나의 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만 올바르게 설정하면 됩니다.
Userspace가 kernel에 보내는 주요 event입니다.
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`을 받지 않은 상태에서도 올 수 있습니다.
Kernel이 userspace transport에 알리는 상태와 output입니다.
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년에 작성했습니다.
GET과 SET은 모두 synchronous이며 request id로 대응됩니다.
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 <[email protected]>
요약·해설
uhid.rst:1-193UHID는 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입니다.
UHID userspace API의 주요 요소입니다.
Virtual device의 대표적인 실행 흐름입니다.