3.7. Human Interface Device API

The Bluetooth Human Interface Device (HID) profile facilitates the use of Bluetooth as a bearer for wireless human interface peripheral devices. The HID device class comprises a large set of devices, such as keyboards, mice, pointer, remote control, etc. That can make use of Bluetooth to provide user input to a host device. HID is a subclass of USB devices. The Bluetooth HID profile fills the gap opened by USB and enables the use of Bluetooth as a wireless bearer for devices conforming to the HID device class specification. This chapter discuss about Affix HID interface.

3.7.1. Basic Architecture

The topology consists of simple wireless point-to-point links between a host device and HID device. In most cases, the host will be master of a Bluetooth piconet with the HID devices connected to as slave devices. However, for dedicated scenarios it is possible for the HID device to take over the role as Bluetooth master. This holds for situations in which the HID device only generates HID reports sporadically, which means that regularly polling the HID device would waste the possibly limited power resources on the device.

Another scenario in which it makes sense that the HID device becomes Bluetooth master is the case the HID device has to generate input for more than one device. Acting as a Bluetooth master the device is able to join all related devices in one piconet and therefore, no scatternet functionality or forwarding of L2CAP data must be supported or used.

For the common case that the host is piconet master, connection establishment is typically initialized by the host. A HID device can be temporarily brought into limited discoverable mode, in which the device answers to a host's inquiry procedure. Once discovered, the host sets up a connection in a page procedure, binding the HID device into its piconet. However, the HID profile also supports the possibility of a HID device to reinitiate a connection, which can be beneficial in case of a host reboot that led to the loss of HID device connection state at the host.

3.7.2. HID Profile

The HID profile species a new protocol on top of L2CAP that encapsulates the HID reports and facilitates other control communication between the HID device and driver for the HID device class on the host. HIDP maintains two L2CAP connections between host and HID device - a control channel, and an interrupt channel. This separation directly emerges from the original HID specification.

The control channel is used to signal status information, to set the power saving and operational states of the HID device, and to query the resource records of a device. The interrupt channel is a data channel, over which the host expects input reports from the HID device, or transmits output reports towards the HID device. As the L2CAP MTU may not suffice to carry complex HID record descriptors, HIDP also supports segmentation and reassembly.

3.7.3. Affix HID API

The kernel-space module affix_hidp has two main tasks. Firstly, it has to connect to the HID device, manage the connection with the device and care for the transmission of the HID reports. Secondly, the kernel module has to take these HID reports, parse them, and put the extracted input events into the input subsystem of the Linux kernel. The two tasks are realized in two different files affix_hid.c and hid.c. However, these files are compiled into one module.

The kernel module is controlled via the ioctl interface. The kernel module implements a set of commands that can be accessed by invoking the ioctl system call on an Affix HCI socket. The interface between kernel-space module and user-space utility contains three ioctl calls. The structures that are given as data by the argument parameter are defined in affix-kernel/include/bluetooth.h. The following ioctl commands are specified:

3.7.3.1. BTIOC_HIDP_MODIFY

The BTIOC_HIDP_MODIFY call is used when a device should be added to the kernel list or a connection to a device should be established. If the device is already known, the existing list entry will be modified. If it is not known, a new list entry will be added. The ioctl call expects a pointer to a hidp_ioc structure. The structure contains various information fields obtained during the SDP query and is defined as follows:

struct hidp_conn_info {
    __u16 parser;
    __u16 rd_size;
    __u8 *rd_data;
    __u8 country;
    __u16 vendor;
    __u16 product;
    __u16 version;
    __u32 flags;
    __u32 idle_to;
    char name[128];
};


struct hidp_ioc {
    struct sockaddr_affix saddr;
    struct hidp_conn_info conn_info;
    __u16 status;
    __u16 cnum;
};

The struct contains the Bluetooth device address, information that have been received by the SDP request , a status field, and a connection number. The status field is a bit mask comprising the flags listed in table below.

Table 3-23. Values of the status bit mask in the hidp_ioc struct

FlagValue
HIDP_STATUS_ACTIVE_ADD0x01
HIDP_STATUS_CONNECTED0x02

The ACTIVE_ADD flag is used for connection initiation. Many HID devices reopen a connection themselves e.g. When a button is hit after a long idle time. For some others the connection has to be initiated by the peer. If this flag is set, the host will actively open a connection to the HID device. Otherwise, it will wait for connection initiation of the HID device.

The CONNECTED flag is used for returning the status of the connection to a HID device known to the kernel module. If set, the device is currently connected, if not, the device is known, but currently not connected.

3.7.3.2. BTIOC_HIDP_DELETE

The BTIOC_HIDP_DELETE command deletes the device from the kernel's list of known HID devices. Thus, a connection is not possible anymore. The only way to reconnect is adding the device again to the list. As with the BTIOC_HIDP_MODIFY command, a pointer to a hidp_ioc struct is expected. In case there is a connection when this call is performed, the connection with the device is closed before.

3.7.3.3. BTIOC_HIDP_GET_LIST

The BTIOC_HIDP_GET_LIST command returns a list of all devices to user-space. It expects a pointer to a hidp_ioc_getlist struct which contains an array of hidp_ioc records to be filled out by the kernel. The number of available hidp_ioc entries must be given in count which returns the number of entries written upon completion. In case the supplied array is not large enough to cover all HID devices, the left field contains the number of devices that do not fit.

The struct returned as argument has the following format:

struct hidp_ioc_getlist {
    int count; /* # of devices in list */
    int left; /* != 0 if more than count devices in list */
    struct hidp_ioc list[0]; /* first element in list */
};