Development of a User-Space Application for an HID Device, Using libhid

When it's time to get a new device working on Linux, every piece of information helps, whether it's reading the hardware documentation, snooping data, reading sample code or even running utilities on a non-Linux OS.

The Matrix is a USB bill validator, sometimes known as a note reader or bill acceptor, made by Validation Technologies International. The bundled software was developed for Microsoft Windows, but fortunately the device comes with low-level technical documentation that defines device-specific aspects, such as flow control, status bytes and local status LEDs.

The device is a Human Interface Device (HID), as identified by an enumeration process upon connection. The Windows device manager reports the device as such, as does usbfs on Linux. This article is specific to this particular HID device, so including all of its code probably is unnecessary, but it should provide help for developing for other HID-class devices.

After some initial research, I decided to develop user-space code using an in-development library called libhid, which provides a cross-platform way to access and interact with USB HID devices. libhid is implemented on top of libusb, so it does not depend directly on the kernel's USB support.

Another option for driving the Matrix is to use libusb directly, but doing so would be re-inventing the libhid wheel. A third option is to implement the Matrix as a kernel module, but it would incur the large overhead of learning kernel particulars. This option also would render the code platform-specific.

Investigation

USB devices are categorized into device classes. A modem is in the communications class, and a speaker falls into the audio class. The HID class mainly consists of devices that people use to control computers. Examples of HID devices are mice, joysticks and force-feedback game controllers. Also included in the HID class are devices that may not require human interaction but do provide data in a similar format to HID-class devices, such as bar-code readers and, in my case, the Matrix note reader.

Information about a USB device is stored in segments of its ROM called descriptors. A diagram of the descriptor structure is provided in Figure 1, where an overall view of the hierarchy can be seen. When a USB device is attached to a USB bus, an enumeration process takes place that equates to the descriptors on the device being read into memory. Information about an HID-class device is contained in its HID report descriptors.

Figure 1. A USB device's descriptors, stored in its ROM, hold information about it.

I plugged the device in to the Linux box in order to read the descriptors and monitor the device, the machine and the communications. I did this to try to get as much information as possible so I could have a better understanding of how to write code for the device.

A key component of these report descriptors is the usage information, which is defined in the USB HID Usage Tables (see the on-line Resources). Usage values describe three basic types of information about the device:

  • Controls—information about the state of the device such as on/off or enable/disable.

  • Data—all other information that passes between the device and the host.

  • Collections—groups of related controls and data.

Taken together, the usage page and usage number define a unique constant that describes a particular type of device or part of that device. For example, on the Generic Desktop usage page (page number 0x01), usage number 0x05 is a game pad, and usage number 0x39 is a hat switch.

Because my device is unique—it isn't a mouse, joystick or something commonly found in the examples of HID-class devices—the usage page is set to 65,440, which is a vendor-defined value. In comparing outputs of lsusb for other HID-class devices, they all had a defined usage page, such as Generic Desktop Controls or Game Controls. Because libhid still is in development, few previous examples of code are available to browse for reference. My work was much like an exploratory investigation.

On Linux, with a standard Debian 2.6.9 kernel and usbutils, I was able to see that Linux recognises the device as a USB HID device, bInterfaceClass = HID, and loads the hiddev kernel module. This module, or piece of kernel code, is a generic driver for HID devices. It is not specific to our needs—it mainly is used for mice, joysticks and the like—so it needs to be detached from the device or disabled (see the Communicating with the Device section).

The device, like all USB devices, is enumerated upon connection to the USB bus. So looking at the output of lsusb -vvv, run as root, for more information is helpful in determining what the device capabilities are. lsusb parses the usbfs filesystem into a more readable format:

[sample lsusb -vvv]

Bus 001 Device 004: ID 0ce5:0003
Device Descriptor:
...
 idVendor           0x0ce5
 idProduct          0x0003
  ...
  Configuration Descriptor:
  ...
   Interface Descriptor:
   ...
     bNumEndpoints        1
     bInterfaceClass      3 Human Interface Devices
     bInterfaceSubClass   0 No Subclass
     bInterfaceProtocol   0 None
     ...
     HID Device Descriptor:
     ...
      Report Descriptor: (length is 32)
       Item(Global):Usage Page,data=[0xa0 0xff]65440
                            (null)
       Item(Local ):Usage, data= [ 0x01 ] 1
                            (null)
       Item(Main  ):Collection, data= [ 0x01 ] 1
                            Application

       Item(Local ):Usage, data= [ 0x03 ] 3
                            (null)
       Item(Global):Logical Minimum,data=[ 0x00 ] 0
       Item(Global):Logical Maximum,data=[ 0xff ]255
       Item(Global): Report Size, data= [ 0x08 ] 8
       Item(Global): Report Count, data= [ 0x05 ] 5
       Item(Main  ): Input, data= [ 0x02 ] 2
        Data Variable Absolute No_Wrap Linear
        Preferred_State No_Null_Position
        Non_Volatile Bitfield

       Item(Local ): Usage, data= [ 0x05 ] 5
                            (null)
       Item(Global):Logical Minimum,data=[ 0x00 ]0
       Item(Global):Logical Maximum,data=[ 0xff ]255
       Item(Global): Report Size, data= [ 0x08 ] 8
       Item(Global): Report Count, data= [ 0x05 ] 5
       Item(Main  ): Output, data= [ 0x02 ] 2
        Data Variable Absolute No_Wrap Linear
        Preferred_State No_Null_Position
        Non_Volatile Bitfield
       Item(Main  ): End Collection, data=none

The above output—some of the information has been omitted—follows the hierarchy depicted in Figure 1. Some values of note are:

  • idVendor and idProduct—unique identifiers for all USB devices, used for identifying and accessing the device in code.

  • bNumEndpoints—lists the number of endpoints available in a device. This value actually means the number of endpoints in addition to the default endpoint, endpoint 0, available in every USB device.

  • bInterfaceClass—the value that determines that a device is an HID-class device.

  • bInterfaceSubClass—the subclass of a device, in this case, HID. For example, the boot interface subclass of the device must be bootable or available to the BIOS, such as a mouse or keyboard.

  • bInterfaceProtocol—the protocol used. Possible values are 0 for none, 1 for keyboard or 2 for mouse; additional information is available in the HID spec.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

HID Browser

Anonymous's picture

I'd like to try this HID browser you mentioned but cannot find it anywhere. Where can I get it?

sadfa

Anonymous's picture

salut

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix