Development of a User-Space Application for an HID Device, Using libhid
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.
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:
[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.
|Making Linux and Android Get Along (It's Not as Hard as It Sounds)||May 16, 2013|
|Drupal Is a Framework: Why Everyone Needs to Understand This||May 15, 2013|
|Home, My Backup Data Center||May 13, 2013|
|Non-Linux FOSS: Seashore||May 10, 2013|
|Trying to Tame the Tablet||May 08, 2013|
|Dart: a New Web Programming Experience||May 07, 2013|
- RSS Feeds
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- New Products
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- Validate an E-Mail Address with PHP, the Right Way
- New Products
- Tech Tip: Really Simple HTTP Server with Python
- Developer Poll
- git-annex assistant
16 min 9 sec ago
- direct cable connection
38 min 39 sec ago
- Agreed on AirDroid. With my
48 min 55 sec ago
- I just learned this
53 min 5 sec ago
1 hour 23 min ago
- not living upto the mobile revolution
4 hours 14 min ago
- Deceptive Advertising and
4 hours 50 min ago
- Let\'s declare that you have
4 hours 50 min ago
- Alterations in Contest Due
4 hours 52 min ago
- At a numbers mindset, your
4 hours 53 min ago
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi
It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
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.