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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Andre

On Fri, Mar 16, 2012 at 6:15 PM, Marcel Holtmann <marcel@xxxxxxxxxxxx> wrote:
> Hi Andre,
>
>> > This driver allows to write I/O drivers in user-space and feed the input
>> > 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
>> > 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 process
>> > 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.
>> > Both input and output data is sent with a uhid_event structure. The "type"
>> > field of the structure specifies what kind of event is sent. There is a
>> > file in Documentation/ explaining the ABI.
>> >
>> > Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxxxxxxx>
>> > ---
>> >  Documentation/hid/uhid.txt |   95 +++++++++
>> >  drivers/hid/Kconfig        |   21 ++
>> >  drivers/hid/Makefile       |    2 +-
>> >  drivers/hid/uhid.c         |  502 ++++++++++++++++++++++++++++++++++++++++++++
>> >  include/linux/uhid.h       |   71 +++++++
>> >  5 files changed, 690 insertions(+), 1 deletion(-)
>> >  create mode 100644 Documentation/hid/uhid.txt
>> >  create mode 100644 drivers/hid/uhid.c
>> >  create 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 @@
>> > +      UHID - User-space I/O driver support for HID subsystem
>> > +     ========================================================
>> > +
>> > +The UHID driver provides an interface for user-space I/O drivers to feed their
>> > +data into the HID subsystem. The HID subsystem then parses the HID reports and
>> > +loads the corresponding HID device driver which then provides the parsed data
>> > +via input-devices to user-space.
>> > +
>> > +This allows user-space to operate on the same level as USB-HID, Bluetooth-HID
>> > +and similar. It does not provide a way to write HID device drivers, though! Use
>> > +HIDRAW for this purpose.
>> > +
>> > +UHID dynamically allocates the minor/major number, meaning that you should rely
>> > +on udev to create the UHID device node. Typically this is created as /dev/uhid.
>> > +
>> > +The UHID API
>> > +------------
>> > +
>> > +For each device that you want to register with the HID core, you need to open a
>> > +separate file-descriptor on /dev/uhid. All communication is done by read()'ing
>> > +or write()'ing "struct uhid_event" objects to the file. Non-blocking operations
>> > +via O_NONBLOCK are supported.
>> > +
>> > +struct uhid_event {
>> > +        __u32 type;
>> > +        ... payload ...
>> > +};
>> > +
>> > +write()
>> > +-------
>> > +write() allows you to modify the state of the device and feed input data into
>> > +the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and
>> > +UHID_INPUT.
>> > +
>> > +  UHID_CREATE:
>> > +  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_create_req and
>> > +  contains information about your device.
>> > +
>> > +  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_CREATE again. There is no need to
>> > +  reopen the character device.
>> > +
>> > +  UHID_INPUT:
>> > +  You must send UHID_CREATE before sending input to the kernel! This event
>> > +  contains a data-payload. This is the raw data that you read from your device.
>> > +  The 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
>> > +UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No
>> > +reaction is required to any of them but you should handle them according to your
>> > +needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
>> > +
>> > +  UHID_START:
>> > +  This is sent when the HID device is started. Consider this as an answer to
>> > +  UHID_CREATE. This is always the first event that is sent. No I/O is possible
>> > +  before you read this.
>> > +
>> > +  UHID_STOP:
>> > +  This is sent when the HID device is stopped. Consider this as an answer to
>> > +  UHID_DESTROY. No further I/O will be possible after receiving this.
>> > +  If the kernel HID device driver closes the device manually (that is, you
>> > +  didn't send UHID_DESTROY) then you should consider this device closed and send
>> > +  an UHID_DESTROY event. You may want to reregister your device, though.
>> > +
>> > +  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_INPUT 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. You should read the payload and forward it to the device. The payload
>> > +  is of type "struct uhid_data_req".
>> > +  This may be received even though you haven't received UHID_OPEN, yet.
>> > +
>> > +  UHID_OUTPUT_EV:
>> > +  Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
>> > +  is called for force-feedback, LED or similar events which are received through
>> > +  an input device by the HID subsystem. You should convert this into raw reports
>> > +  and send them to your device similar to events of type UHID_OUTPUT.
>> > +
>> > +Document by:
>> > +  David Herrmann <dh.herrmann@xxxxxxxxxxxxxx>
>>
>> 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 more
consistent if write() would use the same structure. We can also avoid using
ioctl()'s entirely, they're ugly anyway.

>> 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 look at
the internal handling. You can crop the structure if you want. For events like
UHID_CREATE you can simply send a single struct { __u16 type; }; object. You
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 suggestions.

> Regards
>
> Marcel

Thanks for review
David
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux