Thread (8 messages) 8 messages, 4 authors, 2012-03-26

Re: [RFC 1/1] HID: User-space I/O driver support for HID subsystem

flat view

From: David Herrmann <hidden>
Date: 2012-03-16 19:01:56
Also in: linux-input

Hi Andre

On Fri, Mar 16, 2012 at 6:15 PM, Marcel Holtmann [off-list ref] wrot=
e:
Hi Andre,
quoted
quoted
This driver allows to write I/O drivers in user-space and feed the inp=
ut
quoted
quoted
into the HID subsystem. It operates on the same level as USB-HID and
Bluetooth-HID (HIDP). It does not provide support to write special HID
device drivers but rather provides support for user-space I/O devices =
to
quoted
quoted
feed their data into the kernel HID subsystem. The HID subsystem then
loads the HID device drivers for the device and provides input-devices
based on the user-space HID I/O device.

This driver register a new char-device (/dev/uhid). A user-space proce=
ss
quoted
quoted
has to open this file for each device that it wants to provide to the
kernel. It can then use write/read to communicate with the UHID driver=
.
quoted
quoted
Both input and output data is sent with a uhid_event structure. The "t=
ype"
quoted
quoted
field of the structure specifies what kind of event is sent. There is =
a
quoted
quoted
file in Documentation/ explaining the ABI.

Signed-off-by: David Herrmann <redacted>
---
=A0Documentation/hid/uhid.txt | =A0 95 +++++++++
=A0drivers/hid/Kconfig =A0 =A0 =A0 =A0| =A0 21 ++
=A0drivers/hid/Makefile =A0 =A0 =A0 | =A0 =A02 +-
=A0drivers/hid/uhid.c =A0 =A0 =A0 =A0 | =A0502 +++++++++++++++++++++++=
+++++++++++++++++++++
quoted
quoted
=A0include/linux/uhid.h =A0 =A0 =A0 | =A0 71 +++++++
=A05 files changed, 690 insertions(+), 1 deletion(-)
=A0create mode 100644 Documentation/hid/uhid.txt
=A0create mode 100644 drivers/hid/uhid.c
=A0create mode 100644 include/linux/uhid.h
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
new file mode 100644
index 0000000..67b138d
--- /dev/null
+++ b/Documentation/hid/uhid.txt
@@ -0,0 +1,95 @@
+ =A0 =A0 =A0UHID - User-space I/O driver support for HID subsystem
+ =A0 =A0 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
quoted
quoted
+
+The UHID driver provides an interface for user-space I/O drivers to f=
eed their
quoted
quoted
+data into the HID subsystem. The HID subsystem then parses the HID re=
ports and
quoted
quoted
+loads the corresponding HID device driver which then provides the par=
sed data
quoted
quoted
+via input-devices to user-space.
+
+This allows user-space to operate on the same level as USB-HID, Bluet=
ooth-HID
quoted
quoted
+and similar. It does not provide a way to write HID device drivers, t=
hough! Use
quoted
quoted
+HIDRAW for this purpose.
+
+UHID dynamically allocates the minor/major number, meaning that you s=
hould rely
quoted
quoted
+on udev to create the UHID device node. Typically this is created as =
/dev/uhid.
quoted
quoted
+
+The UHID API
+------------
+
+For each device that you want to register with the HID core, you need=
 to open a
quoted
quoted
+separate file-descriptor on /dev/uhid. All communication is done by r=
ead()'ing
quoted
quoted
+or write()'ing "struct uhid_event" objects to the file. Non-blocking =
operations
quoted
quoted
+via O_NONBLOCK are supported.
+
+struct uhid_event {
+ =A0 =A0 =A0 =A0__u32 type;
+ =A0 =A0 =A0 =A0... payload ...
+};
+
+write()
+-------
+write() allows you to modify the state of the device and feed input d=
ata into
quoted
quoted
+the kernel. The following types are supported: UHID_CREATE, UHID_DEST=
ROY and
quoted
quoted
+UHID_INPUT.
+
+ =A0UHID_CREATE:
+ =A0This creates the internal HID device. No I/O is possible until yo=
u send this
quoted
quoted
+ =A0event to the kernel. The payload is of type struct uhid_create_re=
q and
quoted
quoted
+ =A0contains information about your device.
+
+ =A0UHID_DESTROY:
+ =A0This destroys the internal HID device. No further I/O will be acc=
epted. There
quoted
quoted
+ =A0may still be pending messages that you can receive with read() bu=
t no further
quoted
quoted
+ =A0UHID_INPUT events can be sent to the kernel.
+ =A0You can create a new device by sending UHID_CREATE again. There i=
s no need to
quoted
quoted
+ =A0reopen the character device.
+
+ =A0UHID_INPUT:
+ =A0You must send UHID_CREATE before sending input to the kernel! Thi=
s event
quoted
quoted
+ =A0contains a data-payload. This is the raw data that you read from =
your device.
quoted
quoted
+ =A0The kernel will parse the HID reports and react on it.
+
+read()
+------
+read() will return a queued ouput report. These output reports can be=
 of type
quoted
quoted
+UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUT=
PUT_EV. No
quoted
quoted
+reaction is required to any of them but you should handle them accord=
ing to your
quoted
quoted
+needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
+
+ =A0UHID_START:
+ =A0This is sent when the HID device is started. Consider this as an =
answer to
quoted
quoted
+ =A0UHID_CREATE. This is always the first event that is sent. No I/O =
is possible
quoted
quoted
+ =A0before you read this.
+
+ =A0UHID_STOP:
+ =A0This is sent when the HID device is stopped. Consider this as an =
answer to
quoted
quoted
+ =A0UHID_DESTROY. No further I/O will be possible after receiving thi=
s.
quoted
quoted
+ =A0If the kernel HID device driver closes the device manually (that =
is, you
quoted
quoted
+ =A0didn't send UHID_DESTROY) then you should consider this device cl=
osed and send
quoted
quoted
+ =A0an UHID_DESTROY event. You may want to reregister your device, th=
ough.
quoted
quoted
+
+ =A0UHID_OPEN:
+ =A0This is sent when the HID device is opened. That is, the data tha=
t the HID
quoted
quoted
+ =A0device provides is read by some other process. You may ignore thi=
s event but
quoted
quoted
+ =A0it is useful for power-management. As long as you haven't receive=
d this event
quoted
quoted
+ =A0there is actually no other process that reads your data so there =
is no need to
quoted
quoted
+ =A0send UHID_INPUT events to the kernel.
+
+ =A0UHID_CLOSE:
+ =A0This is sent when there are no more processes which read the HID =
data. It is
quoted
quoted
+ =A0the counterpart of UHID_OPEN and you may as well ignore this even=
t.
quoted
quoted
+
+ =A0UHID_OUTPUT:
+ =A0This is sent if the HID device driver wants to send raw data to t=
he I/O
quoted
quoted
+ =A0device. You should read the payload and forward it to the device.=
 The payload
quoted
quoted
+ =A0is of type "struct uhid_data_req".
+ =A0This may be received even though you haven't received UHID_OPEN, =
yet.
quoted
quoted
+
+ =A0UHID_OUTPUT_EV:
+ =A0Same as UHID_OUTPUT but this contains a "struct input_event" as p=
ayload. This
quoted
quoted
+ =A0is called for force-feedback, LED or similar events which are rec=
eived through
quoted
quoted
+ =A0an input device by the HID subsystem. You should convert this int=
o raw reports
quoted
quoted
+ =A0and send them to your device similar to events of type UHID_OUTPU=
T.
quoted
quoted
+
+Document by:
+ =A0David Herrmann <dh.herrmann@googlemail.com>
What do you think about using ioctl() to handle creating, destroying
and configuring internal hid devices and leave read() and write() to
handle HID reports?
I need to notify user-space about START/STOP/OPEN/CLOSE/... signals so read=
()
will always need some event-structure. Therefore, I thought it would be mor=
e
consistent if write() would use the same structure. We can also avoid using
ioctl()'s entirely, they're ugly anyway.
quoted
This way, at user-space, we wouldn't need to build uhid_event messages
for every HID report we get. We would just write() the HID report
right away.
we could also just use scatter gather writes and reads. So that is not
really a problem as long as the "header" has a fixed length.
What is the problem with building uhid_event structures? Is it performance?
Do you really think one single memcpy() is that important?

If the size of the uhid_event structure is a problem, you should have a loo=
k at
the internal handling. You can crop the structure if you want. For events l=
ike
UHID_CREATE you can simply send a single struct { __u16 type; }; object. Yo=
u
just need to make sure that if the event-type requires a payload, then
the payload
must be included.
However, I also considered using a pointer instead of the 4096-bytes array =
so we
would avoid that heavy payload for lazy programmers. I am open for suggesti=
ons.
Regards

Marcel
Thanks for review
David
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help