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.

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: