Re: [PATCH] HID: Add HID transport driver documentation

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

 



On Mon, Feb 3, 2014 at 11:50 AM, David Herrmann <dh.herrmann@xxxxxxxxx> wrote:
> Hi
>
> On Sat, Feb 1, 2014 at 12:18 AM, Benjamin Tissoires
> <benjamin.tissoires@xxxxxxxxx> wrote:
>> On Wed, Jan 29, 2014 at 10:35 AM, David Herrmann <dh.herrmann@xxxxxxxxx> wrote:
>>> Hi
>>>
>>> On Wed, Jan 29, 2014 at 4:28 PM, Frank Praznik <frank.praznik@xxxxxxxxx> wrote:
>>>> Add David Herrmann's documentation for the new low-level HID transport driver
>>>> functions.
>>>>
>>>> Signed-off-by: Frank Praznik <frank.praznik@xxxxxxxxx>
>>>
>>> If you copy code, you really should keep the signed-off-by chain. A
>>> signed-off-by in kernel context means that you either wrote the code
>>> or have permission to copy it. See here:
>>> http://developercertificate.org/ (which is a public copy of the
>>> kernel's signed-off-by practice).
>>> If you copy code unchanged, it's common practice to even keep the
>>> "Author" field via "git commit --author", but that's optional.
>>>
>>> Anyhow, patch is good, thanks for picking it up!
>>>
>>> Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxx>
>>>
>>> Putting Benjamin on CC as he reviewed the patch last time and might
>>> have some more comments (or his final reviewed-by).
>>>
>>
>> Thanks David. I am globally happy with it, but I have a little remark:
>>
>>> Thanks!
>>> David
>>>
>>>> ---
>>>>
>>>>  Sorry, I forgot to include this in the original patch set.
>>>>
>>>>  Documentation/hid/hid-transport.txt | 324 ++++++++++++++++++++++++++++++++++++
>>>>  1 file changed, 324 insertions(+)
>>>>  create mode 100644 Documentation/hid/hid-transport.txt
>>>>
>>>> diff --git a/Documentation/hid/hid-transport.txt b/Documentation/hid/hid-transport.txt
>>>> new file mode 100644
>>>> index 0000000..14b1c18
>>>> --- /dev/null
>>>> +++ b/Documentation/hid/hid-transport.txt
>>>> @@ -0,0 +1,324 @@
>>>> +                          HID I/O Transport Drivers
>>>> +                         ===========================
>>>> +
>>>> +The HID subsystem is independent of the underlying transport driver. Initially,
>>>> +only USB was supported, but other specifications adopted the HID design and
>>>> +provided new transport drivers. The kernel includes at least support for USB,
>>>> +Bluetooth, I2C and user-space I/O drivers.
>>>> +
>>>> +1) HID Bus
>>>> +==========
>>>> +
>>>> +The HID subsystem is designed as a bus. Any I/O subsystem may provide HID
>>>> +devices and register them with the HID bus. HID core then loads generic device
>>>> +drivers on top of it. The transport drivers are responsible of raw data
>>>> +transport and device setup/management. HID core is responsible of
>>>> +report-parsing, report interpretation and the user-space API. Device specifics
>>>> +and quirks are handled by all layers depending on the quirk.
>>>> +
>>>> + +-----------+  +-----------+            +-----------+  +-----------+
>>>> + | Device #1 |  | Device #i |            | Device #j |  | Device #k |
>>>> + +-----------+  +-----------+            +-----------+  +-----------+
>>>> +          \\      //                              \\      //
>>>> +        +------------+                          +------------+
>>>> +        | I/O Driver |                          | I/O Driver |
>>>> +        +------------+                          +------------+
>>>> +              ||                                      ||
>>>> +     +------------------+                    +------------------+
>>>> +     | Transport Driver |                    | Transport Driver |
>>>> +     +------------------+                    +------------------+
>>>> +                       \___                ___/
>>>> +                           \              /
>>>> +                          +----------------+
>>>> +                          |    HID Core    |
>>>> +                          +----------------+
>>>> +                           /  |        |  \
>>>> +                          /   |        |   \
>>>> +             ____________/    |        |    \_________________
>>>> +            /                 |        |                      \
>>>> +           /                  |        |                       \
>>>> + +----------------+  +-----------+  +------------------+  +------------------+
>>>> + | Generic Driver |  | MT Driver |  | Custom Driver #1 |  | Custom Driver #2 |
>>>> + +----------------+  +-----------+  +------------------+  +------------------+
>>>> +
>>>> +Example Drivers:
>>>> +  I/O: USB, I2C, Bluetooth-l2cap
>>>> +  Transport: USB-HID, I2C-HID, BT-HIDP
>>>> +
>>>> +Everything below "HID Core" is simplified in this graph as it is only of
>>>> +interest to HID device drivers. Transport drivers do not need to know the
>>>> +specifics.
>>>> +
>>>> +1.1) Device Setup
>>>> +-----------------
>>>> +
>>>> +I/O drivers normally provide hotplug detection or device enumeration APIs to the
>>>> +transport drivers. Transport drivers use this to find any suitable HID device.
>>>> +They allocate HID device objects and register them with HID core. Transport
>>>> +drivers are not required to register themselves with HID core. HID core is never
>>>> +aware of which transport drivers are available and is not interested in it. It
>>>> +is only interested in devices.
>>>> +
>>>> +Transport drivers attach a constant "struct hid_ll_driver" object with each
>>>> +device. Once a device is registered with HID core, the callbacks provided via
>>>> +this struct are used by HID core to communicate with the device.
>>>> +
>>>> +Transport drivers are responsible of detecting device failures and unplugging.
>>>> +HID core will operate a device as long as it is registered regardless of any
>>>> +device failures. Once transport drivers detect unplug or failure events, they
>>>> +must unregister the device from HID core and HID core will stop using the
>>>> +provided callbacks.
>>>> +
>>>> +1.2) Transport Driver Requirements
>>>> +----------------------------------
>>>> +
>>>> +The terms "asynchronous" and "synchronous" in this document describe the
>>>> +transmission behavior regarding acknowledgements. An asynchronous channel must
>>>> +not perform any synchronous operations like waiting for acknowledgements or
>>>> +verifications. Generally, HID calls operating on asynchronous channels must be
>>>> +running in atomic-context just fine.
>>>> +On the other hand, synchronous channels can be implemented by the transport
>>>> +driver in whatever way they like. They might just be the same as asynchronous
>>>> +channels, but they can also provide acknowledgement reports, automatic
>>>> +retransmission on failure, etc. in a blocking manner. If such functionality is
>>>> +required on asynchronous channels, a transport-driver must implement that via
>>>> +its own worker threads.
>>>> +
>>>> +HID core requires transport drivers to follow a given design. A Transport
>>>> +driver must provide two bi-directional I/O channels to each HID device. These
>>>> +channels must not necessarily be bi-directional in the hardware itself. A
>>>> +transport driver might just provide 4 uni-directional channels. Or it might
>>>> +multiplex all four on a single physical channel. However, in this document we
>>>> +will describe them as two bi-directional channels as they have several
>>>> +properties in common.
>>>> +
>>>> + - Interrupt Channel (intr): The intr channel is used for asynchronous data
>>>> +   reports. No management commands or data acknowledgements are sent on this
>>>> +   channel. Any unrequested incoming or outgoing data report must be sent on
>>>> +   this channel and is never acknowledged by the remote side. Devices usually
>>>> +   send their input events on this channel. Outgoing events are normally
>>>> +   not send via intr, except if high throughput is required.
>>>> + - Control Channel (ctrl): The ctrl channel is used for synchronous requests and
>>>> +   device management. Unrequested data input events must not be sent on this
>>>> +   channel and are normally ignored. Instead, devices only send management
>>>> +   events or answers to host requests on this channel.
>>>> +   The control-channel is used for direct blocking queries to the device
>>>> +   independent of any events on the intr-channel.
>>>> +   Outgoing reports are usually sent on the ctrl channel via synchronous
>>>> +   SET_REPORT requests.
>>>> +
>>>> +Communication between devices and HID core is mostly done via HID reports. A
>>>> +report can be of one of three types:
>>>> +
>>>> + - INPUT Report: Input reports provide data from device to host. This
>>>> +   data may include button events, axis events, battery status or more. This
>>>> +   data is generated by the device and sent to the host with or without
>>>> +   requiring explicit requests. Devices can choose to send data continuously or
>>>> +   only on change.
>>>> + - OUTPUT Report: Output reports change device states. They are sent from host
>>>> +   to device and may include LED requests, rumble requests or more. Output
>>>> +   reports are never sent from device to host, but a host can retrieve their
>>>> +   current state.
>>>> +   Hosts may choose to send output reports either continuously or only on
>>>> +   change.
>>>> + - FEATURE Report: Feature reports are used for specific static device features
>>>> +   and never reported spontaneously. A host can read and/or write them to access
>>>> +   data like battery-state or device-settings.
>>>> +   Feature reports are never sent without requests. A host must explicitly set
>>>> +   or retrieve a feature report. This also means, feature reports are never sent
>>>> +   on the intr channel as this channel is asynchronous.
>>>> +
>>>> +INPUT and OUTPUT reports can be sent as pure data reports on the intr channel.
>>>> +For INPUT reports this is the usual operational mode. But for OUTPUT reports,
>>>> +this is rarely done as OUTPUT reports are normally quite scarce. But devices are
>>>> +free to make excessive use of asynchronous OUTPUT reports (for instance, custom
>>>> +HID audio speakers make great use of it).
>>>> +
>>>> +Plain reports must not be sent on the ctrl channel, though. Instead, the ctrl
>>>> +channel provides synchronous GET/SET_REPORT requests. Plain reports are only
>>>> +allowed on the intr channel and are the only means of data there.
>>>> +
>>>> + - GET_REPORT: A GET_REPORT request has a report ID as payload and is sent
>>>> +   from host to device. The device must answer with a data report for the
>>>> +   requested report ID on the ctrl channel as a synchronous acknowledgement.
>>>> +   Only one GET_REPORT request can be pending for each device. This restriction
>>>> +   is enforced by HID core as several transport drivers don't allow multiple
>>>> +   simultaneous GET_REPORT requests.
>>>> +   Note that data reports which are sent as answer to a GET_REPORT request are
>>>> +   not handled as generic device events. That is, if a device does not operate
>>>> +   in continuous data reporting mode, an answer to GET_REPORT does not replace
>>>> +   the raw data report on the intr channel on state change.
>>>> +   GET_REPORT is only used by custom HID device drivers to query device state.
>>>> +   Normally, HID core caches any device state so this request is not necessary
>>>> +   on devices that follow the HID specs except during device initialization to
>>>> +   retrieve the current state.
>>>> +   GET_REPORT requests can be sent for any of the 3 report types and shall
>>>> +   return the current report state of the device. However, OUTPUT reports as
>>>> +   payload may be blocked by the underlying transport driver if the
>>>> +   specification does not allow them.
>>>> + - SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It is
>>>> +   sent from host to device and a device must update it's current report state
>>>> +   according to the given data. Any of the 3 report types can be used. However,
>>>> +   INPUT reports as payload might be blocked by the underlying transport driver
>>>> +   if the specification does not allow them.
>>>> +   A device must answer with a synchronous acknowledgement. However, HID core
>>>> +   does not require transport drivers to forward this acknowledgement to HID
>>>> +   core.
>>>> +   Same as for GET_REPORT, only one SET_REPORT can be pending at a time. This
>>>> +   restriction is enforced by HID core as some transport drivers do not support
>>>> +   multiple synchronous SET_REPORT requests.
>>>> +
>>>> +Other ctrl-channel requests are supported by USB-HID but are not available
>>>> +(or deprecated) in most other transport level specifications:
>>>> +
>>>> + - GET/SET_IDLE: Only used by USB-HID and I2C-HID.
>>>> + - GET/SET_PROTOCOL: Not used by HID core.
>>>> + - RESET: Used by I2C-HID, not hooked up in HID core.
>>>> + - SET_POWER: Used by I2C-HID, not hooked up in HID core.
>>>> +
>>>> +2) HID API
>>>> +==========
>>>> +
>>>> +2.1) Initialization
>>>> +-------------------
>>>> +
>>>> +Transport drivers normally use the following procedure to register a new device
>>>> +with HID core:
>>>> +
>>>> +       struct hid_device *hid;
>>>> +       int ret;
>>>> +
>>>> +       hid = hid_allocate_device();
>>>> +       if (IS_ERR(hid)) {
>>>> +               ret = PTR_ERR(hid);
>>>> +               goto err_<...>;
>>>> +       }
>>>> +
>>>> +       strlcpy(hid->name, <device-name-src>, 127);
>>>> +       strlcpy(hid->phys, <device-phys-src>, 63);
>>>> +       strlcpy(hid->uniq, <device-uniq-src>, 63);
>>>> +
>>>> +       hid->ll_driver = &custom_ll_driver;
>>>> +       hid->bus = <device-bus>;
>>>> +       hid->vendor = <device-vendor>;
>>>> +       hid->product = <device-product>;
>>>> +       hid->version = <device-version>;
>>>> +       hid->country = <device-country>;
>>>> +       hid->dev.parent = <pointer-to-parent-device>;
>>>> +       hid->driver_data = <transport-driver-data-field>;
>>>> +
>>>> +       ret = hid_add_device(hid);
>>>> +       if (ret)
>>>> +               goto err_<...>;
>>>> +
>>>> +Once hid_add_device() is entered, HID core might use the callbacks provided in
>>>> +"custom_ll_driver". Note that fields like "country" can be ignored by underlying
>>>> +transport-drivers if not supported.
>>>> +
>>>> +To unregister a device, use:
>>>> +
>>>> +       hid_destroy_device(hid);
>>>> +
>>>> +Once hid_destroy_device() returns, HID core will no longer make use of any
>>>> +driver callbacks.
>>>> +
>>>> +2.2) hid_ll_driver operations
>>>> +-----------------------------
>>>> +
>>>> +The available HID callbacks are:
>>>> + - int (*start) (struct hid_device *hdev)
>>>> +   Called from HID device drivers once they want to use the device. Transport
>>>> +   drivers can choose to setup their device in this callback. However, normally
>>>> +   devices are already set up before transport drivers register them to HID core
>>>> +   so this is mostly only used by USB-HID.
>>>> +
>>>> + - void (*stop) (struct hid_device *hdev)
>>>> +   Called from HID device drivers once they are done with a device. Transport
>>>> +   drivers can free any buffers and deinitialize the device. But note that
>>>> +   ->start() might be called again if another HID device driver is loaded on the
>>>> +   device.
>>>> +   Transport drivers are free to ignore it and deinitialize devices after they
>>>> +   destroyed them via hid_destroy_device().
>>>> +
>>>> + - int (*open) (struct hid_device *hdev)
>>>> +   Called from HID device drivers once they are interested in data reports.
>>>> +   Usually, while user-space didn't open any input API/etc., device drivers are
>>>> +   not interested in device data and transport drivers can put devices asleep.
>>>> +   However, once ->open() is called, transport drivers must be ready for I/O.
>>>> +   ->open() calls are nested for each client that opens the HID device.
>>>> +
>>>> + - void (*close) (struct hid_device *hdev)
>>>> +   Called from HID device drivers after ->open() was called but they are no
>>>> +   longer interested in device reports. (Usually if user-space closed any input
>>>> +   devices of the driver).
>>>> +   Transport drivers can put devices asleep and terminate any I/O of all
>>>> +   ->open() calls have been followed by a ->close() call. However, ->start() may
>>>> +   be called again if the device driver is interested in input reports again.
>>>> +
>>>> + - int (*parse) (struct hid_device *hdev)
>>>> +   Called once during device setup after ->start() has been called. Transport
>>>> +   drivers must read the HID report-descriptor from the device and tell HID core
>>>> +   about it via hid_parse_report().
>>>> +
>>>> + - int (*power) (struct hid_device *hdev, int level)
>>>> +   Called by HID core to give PM hints to transport drivers. Usually this is
>>>> +   analogical to the ->open() and ->close() hints and redundant.
>>>> +
>>>> + - void (*request) (struct hid_device *hdev, struct hid_report *report,
>>>> +                    int reqtype)
>>>> +   Send an HID request on the ctrl channel. "report" contains the report that
>>>> +   should be sent and "reqtype" the request type. Request-type can be
>>>> +   HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
>>>> +   This callback is optional. If not provided, HID core will assemble a raw
>>>> +   report following the HID specs and send it via the ->raw_request() callback.
>>
>> This is not true currently. Aren't we missing a commit in the original series?
>> But I would love seeing this come true.
>
> You're talking about the ->request() to ->raw_request() conversion?
> Indeed, that hasn't been implemented. But it should be rather easy to
> do, right? I will prepare a patch for that so we can apply this
> documentation unchanged.

Don't bother doing it, I have already made it yesterday :)

The documentation would still need to be cleaned to remove
hid_input_event callback... So I can take it in the next round of
ll_transport cleanup if you are ok too.

CHeers,
Benjamin
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux