Channels ▼

Al Williams

Dr. Dobb's Bloggers

USB Clickity Clack

March 02, 2012

A device by itself isn't enough to communicate. All device I/O in USB occurs with an endpoint. What's more, every device has to have at least a control endpoint (endpoint 0), although you can have multiple input or output endpoints.

HID devices always have a control endpoint and an input endpoint. Many also use an output endpoint. All data appears in a special format called a report.

If you had to actually write a custom driver for USB devices, it would be a lot of work and a lot of repeated work. However, most platforms have support for user programs to directly work with USB or HID devices. For example, the WINUSB driver on Windows will work. A better answer, though, is to use libusb. This library provides a stable API to a variety of platform-specific back ends. Practically, that means you should be able to communicate the same way using Linux, Windows, or Mac.

There are also some wrappers (often around libusb) specifically for HID devices. One example is HIDAPI. I didn't use HIDAPI, however, since it was simple enough to directly use libusb for my purposes. It is worth noting that there are two versions of libusb. The 1.0 version is the one you should be using, but there are many examples on the Internet using the 0.1 library, which is older. However, there is a translation layer for the 1.0 library if you want to make the old-style calls.

If you look at the libusb API, you will see that many of the APIs are for finding a specific USB device. For now, these don't matter much because I know what device I want. By the same token, since I have an already-built report, I can defer worrying about the exact format of the report.

Here's a stripped down version of the code (the full version is available online):

int main(int argc, char *argv[])
{
  struct libusb_device_handle *dev;
  
// init USB lib (this is the 1.0 lib)
  if (libusb_init(NULL)<0) 
    {
      printf("Can't open libusb\n");
      return 1;
    }
  // Open the device
  dev=libusb_open_device_with_vid_pid(NULL,VID,PID);
  if (!dev)
    {
      printf("Can't find device\n");
      rv=1;
    }
  else
    {
      // unhook the kernel's driver on 
      rv=libusb_detach_kernel_driver(dev,INTERFACE);
        // Get the interface for us
      rv=libusb_claim_interface(dev,INTERFACE);
        // Write the command
      rv=libusb_control_transfer(dev,
           LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|
  	   LIBUSB_ENDPOINT_OUT,   // type of write
	   0x9,     // request type (SET_REPORT)
	   0x300,    // value (0x3 = feature, 00=report ID)
 	   INTERFACE,        // INTERFACE
  	   cdata,     // data packet
   	   sizeof(cdata),  // byte count
	   1000);   // timeout
  
    // put everything back and close up
      libusb_release_interface(dev,INTERFACE);
      libusb_attach_kernel_driver(dev,INTERFACE);
      libusb_close(dev);
      libusb_exit(NULL);
    }
  }

Between the comments and the API documentation, you shouldn't have much trouble deciphering the operation. The keyboard's interface for the special key enable is #2 (INTERFACE in the program). The cdata array holds the reverse-engineered report necessary. VID and PID are just #defines that hold the vendor and product IDs, respectively.

Did it work? Yes it did. After the program runs, Linux is able to see the special keys and I can use any number of methods to map them to actions. Next time, I'll talk more about libusb and how you can apply this library to your own designs.

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video