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 andprovided 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 HIDdevices and register them with the HID bus. HID core then loads generic devicedrivers on top of it. The transport drivers are responsible for raw datatransport and device setup/management. HID core is responsible forreport-parsing, report interpretation and the user-space API. Device specificsand 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 ofinterest to HID device drivers. Transport drivers do not need to know thespecifics.
1.1) Device Setup¶
I/O drivers normally provide hotplug detection or device enumeration APIs to thetransport drivers. Transport drivers use this to find any suitable HID device.They allocate HID device objects and register them with HID core. Transportdrivers are not required to register themselves with HID core. HID core is neveraware of which transport drivers are available and is not interested in it. Itis only interested in devices.
Transport drivers attach a constant “structhid_ll_driver” object with eachdevice. Once a device is registered with HID core, the callbacks provided viathisstructare used by HID core to communicate with the device.
Transport drivers are responsible for detecting device failures and unplugging.HID core will operate a device as long as it is registered regardless of anydevice failures. Once transport drivers detect unplug or failure events, theymust unregister the device from HID core and HID core will stop using theprovided callbacks.
1.2) Transport Driver Requirements¶
The terms “asynchronous” and “synchronous” in this document describe thetransmission behavior regarding acknowledgements. An asynchronous channel mustnot perform any synchronous operations like waiting for acknowledgements orverifications. Generally, HID calls operating on asynchronous channels must berunning in atomic-context just fine.On the other hand, synchronous channels can be implemented by the transportdriver in whatever way they like. They might just be the same as asynchronouschannels, but they can also provide acknowledgement reports, automaticretransmission on failure, etc. in a blocking manner. If such functionality isrequired on asynchronous channels, a transport-driver must implement that viaits own worker threads.
HID core requires transport drivers to follow a given design. A Transportdriver must provide two bi-directional I/O channels to each HID device. Thesechannels must not necessarily be bi-directional in the hardware itself. Atransport driver might just provide 4 uni-directional channels. Or it mightmultiplex all four on a single physical channel. However, in this document wewill describe them as two bi-directional channels as they have severalproperties in common.
Interrupt Channel (intr): The intr channel is used for asynchronous datareports. No management commands or data acknowledgements are sent on thischannel. Any unrequested incoming or outgoing data report must be sent onthis channel and is never acknowledged by the remote side. Devices usuallysend their input events on this channel. Outgoing events are normallynot sent via intr, except if high throughput is required.
Control Channel (ctrl): The ctrl channel is used for synchronous requests anddevice management. Unrequested data input events must not be sent on thischannel and are normally ignored. Instead, devices only send managementevents or answers to host requests on this channel.The control-channel is used for direct blocking queries to the deviceindependent of any events on the intr-channel.Outgoing reports are usually sent on the ctrl channel via synchronousSET_REPORT requests.
Communication between devices and HID core is mostly done via HID reports. Areport can be of one of three types:
INPUT Report: Input reports provide data from device to host. Thisdata may include button events, axis events, battery status or more. Thisdata is generated by the device and sent to the host with or withoutrequiring explicit requests. Devices can choose to send data continuously oronly on change.
OUTPUT Report: Output reports change device states. They are sent from hostto device and may include LED requests, rumble requests or more. Outputreports are never sent from device to host, but a host can retrieve theircurrent state.Hosts may choose to send output reports either continuously or only onchange.
FEATURE Report: Feature reports are used for specific static device featuresand never reported spontaneously. A host can read and/or write them to accessdata like battery-state or device-settings.Feature reports are never sent without requests. A host must explicitly setor retrieve a feature report. This also means, feature reports are never senton 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 arefree to make excessive use of asynchronous OUTPUT reports (for instance, customHID audio speakers make great use of it).
Plain reports must not be sent on the ctrl channel, though. Instead, the ctrlchannel provides synchronous GET/SET_REPORT requests. Plain reports are onlyallowed 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 sentfrom host to device. The device must answer with a data report for therequested report ID on the ctrl channel as a synchronous acknowledgement.Only one GET_REPORT request can be pending for each device. This restrictionis enforced by HID core as several transport drivers don’t allow multiplesimultaneous GET_REPORT requests.Note that data reports which are sent as answer to a GET_REPORT request arenot handled as generic device events. That is, if a device does not operatein continuous data reporting mode, an answer to GET_REPORT does not replacethe 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 necessaryon devices that follow the HID specs except during device initialization toretrieve the current state.GET_REPORT requests can be sent for any of the 3 report types and shallreturn the current report state of the device. However, OUTPUT reports aspayload may be blocked by the underlying transport driver if thespecification does not allow them.
SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It issent from host to device and a device must update its current report stateaccording 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 driverif the specification does not allow them.A device must answer with a synchronous acknowledgement. However, HID coredoes not require transport drivers to forward this acknowledgement to HIDcore.Same as for GET_REPORT, only one SET_REPORT can be pending at a time. Thisrestriction is enforced by HID core as some transport drivers do not supportmultiple 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 devicewith HID core:
struct hid_device *hid;int ret;hid = hid_allocate_device();if (IS_ERR(hid)) { ret = PTR_ERR(hid); goto err_<...>;}strscpy(hid->name, <device-name-src>, sizeof(hid->name));strscpy(hid->phys, <device-phys-src>, sizeof(hid->phys));strscpy(hid->uniq, <device-uniq-src>, sizeof(hid->uniq));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_<...>;Oncehid_add_device() is entered, HID core might use the callbacks provided in“custom_ll_driver”. Note that fields like “country” can be ignored by underlyingtransport-drivers if not supported.
To unregister a device, use:
hid_destroy_device(hid);
Oncehid_destroy_device() returns, HID core will no longer make use of anydriver 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. Transportdrivers can choose to setup their device in this callback. However, normallydevices are already set up before transport drivers register them to HID coreso 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. Transportdrivers can free any buffers and deinitialize the device. But note that->
start()might be called again if another HID device driver is loaded on thedevice.Transport drivers are free to ignore it and deinitialize devices after theydestroyed 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 arenot 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 nolonger interested in device reports. (Usually if user-space closed any inputdevices 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()maybe 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. Transportdrivers must read the HID report-descriptor from the device and tell HID coreabout it viahid_parse_report().int (*power) (struct hid_device *hdev, int level)Called by HID core to give PM hints to transport drivers. Usually this isanalogical to the ->open() and ->close() hints and redundant.
void (*request) (struct hid_device *hdev, struct hid_report *report, int reqtype)Send a HID request on the ctrl channel. “report” contains the report thatshould be sent and “reqtype” the request type. Request-type can beHID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
This callback is optional. If not provided, HID core will assemble a rawreport following the HID specs and send it via the ->
raw_request()callback.The transport driver is free to implement this asynchronously.int (*wait) (struct hid_device *hdev)Used by HID core before calling ->
request()again. A transport driver can useit to wait for any pending requests to complete if only one request isallowed at a time.int (*raw_request) (struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t count, unsigned char rtype, int reqtype)Same as ->
request()but provides the report as raw buffer. This request shallbe synchronous. A transport driver must not use ->wait()to complete suchrequests. This request is mandatory and hid core will reject the device ifit is missing.int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)Send raw output report via intr channel. Used by some HID device driverswhich require high throughput for outgoing requests on the intr channel. Thismust not cause SET_REPORT calls! This must be implemented as asynchronousoutput report on the intr channel!
int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
2.3) Data Path¶
Transport drivers are responsible of reading data from I/O devices. They musthandle any I/O-related state-tracking themselves. HID core does not implementprotocol handshakes or other management commands which can be required by thegiven HID transport specification.
Every raw data packet read from a device must be fed into HID core viahid_input_report(). You must specify the channel-type (intr or ctrl) and reporttype (input/output/feature). Under normal conditions, only input reports areprovided via this API.
Responses to GET_REPORT requests via ->request() must also be provided via thisAPI. Responses to ->raw_request() are synchronous and must be intercepted by thetransport driver and not passed tohid_input_report().Acknowledgements to SET_REPORT requests are not of interest to HID core.
Written 2013, David Herrmann <dh.herrmann@gmail.com>