Here’s another “hairball” post about USB devices and drivers on Linux. I wish some expert would write the definitive “here’s how to reverse-engineer a USB device and write a new USB driver” guide. I am definitely not that expert.
Once you reverse engineer a Windows USB device enough to know how it works, you’re ready to try talking to the device under Linux. Here are a few tips.
lsusb to list devices from a command-line.
On Ubuntu 7.10, usbview (use “sudo apt-get install usbview” to install it) is broken. It says “Can not open the file /proc/bus/usb/devices Verify that you have USB compiled into your kernel, have the USB core modules loaded, and have the usbdevfs filesystem mounted.” It turns out that Ubuntu decided to drop support for /proc/bus/usb devices. You can still find USB devices under /dev/bus/usb/ on Ubuntu, but they are special binary files.
usbmon is a Linux kernel module that lets you monitor USB events: http://people.redhat.com/zaitcev/linux/OLS05_zaitcev.pdf . The text file format is pretty terse (see the PDF for some details), but if you’ve installed Linux kernel source code, check Documentation/usb/usbmon.txt for more info. Note that USBMon is a tool with a graphical user interface (GUI) that is based on usbmon. I believe that usbmon operates by using instrumentation hooks in the usbcore Linux kernel module. usbmon normally outputs only text, although Eric Preston reported adding a binary interface to usbmon.
You can trace how talking to a USB device under Linux has gotten easier over the years by reading the sequence of articles that Greg Kroah-Hartman has written for Linux Journal over the years. Let’s examine a few of the articles:
October 2001: How to Write a Linux USB Device Driver. Greg walks through nitty gritty details for using a program usb-skeleton.c that he wrote. Aspiring writers of drivers have to learn quite a bit of kernel hacking.
April 2004: Writing a Simple USB Driver. Greg writes a simple driver for a USB lamp. The driver still sits in kernel space, but exposes some functionality to the user through sysfs. What the heck is sysfs? According to the Wikipedia page, “Sysfs is a virtual file system provided by the 2.6 Linux kernel and it replaced the old deprecated devfs which use in 2.4 series of stable kernels. Sysfs exports information about devices and drivers from the kernel device model to userspace, and is also used for configuration.” Pretty handy. This article is also notable because Greg mentions a couple ways to reverse-engineer an unknown USB protocol: 1) sniff the USB events with Windows software such as SnoopyPro, or 2) run Windows on top of Linux using virtualization software such as VMWare. When you plug in a USB device, VMWare can make the device available to the Windows instance. Windows happily talks with the USB device, unaware that because Linux is sitting between Windows and the USB device, Linux gets to see (and can dump) all the communication that is happening between Windows and the USB device.
June 2004: Writing a Real Driver — In User Space. Greg has now left the kernel behind for the ease of talking to a USB device from user space. This article covers three things that make like easier.
1. usbfs. Originally called usbdevfs, usbfs is a way for user space programs to read/write data to USB devices. The method of talking to the USB devices are ioctl (“input/output control”) function calls to special files, where each file represents a USB device. If you’ve use ioctl before, you’ll know that this is still a pretty down-to-the-metal way to talk to hardware.
2. libusb. This is where life really starts to get good. libusb is a library radically simplifies talking to USB devices. Even better, it runs on many types of UNIX besides Linux (including Mac OS X). You can read the official libusb documentation, but it lacks a good “talk to a simple device” example. I also enjoyed this overview of libusb.
3. Example source code. Is there anything better when you’re delving into a new library than example source code? Greg gives a short program that echoes his previous article. In just a few lines of code, he shows how to turn on an LED in a USB lamp.
There are a couple wrinkles with the sample code. First, there are at least a few errors in the code on the Linux Journal website. A C programmer can look at code like
usb_handle = usb_open(usb_dev);
if (usb_handle == NULL) {
fprintf(stderr,
goto exit;
}
usb_handle = usb_open(usb_dev);
if (usb_handle == NULL) {
fprintf(stderr, "Not able to claim the USB devicen");
goto exit;
}
and say “Hmm. That first fprintf doesn’t have a closing parenthesis. For that matter, why call usb_open() twice and overwrite usb_handle the second time?” So something got scrambled in the code listing. I recommend checking out this simple usbradio program as another short example of how to use libusb.
Second, Greg doesn’t really say how to compile the program. On Ubuntu 7.10 (Gutsy Gibbon), I had to install a few packages. I think I had to do “sudo apt-get install gcc build-essential libusb-dev” to get everything I needed. Then if your program is called talk-to-usb.c, you would compile the program with “gcc -o talk-to-usb talk-to-usb.c -lusb”. (The “-lusb” tells the compiler to use the libusb library when linking in code.)
August 2004: Snooping the USB Data Stream. This is a really fascinating article. Greg is given an unknown USB device and told to make it work on Linux. It turns out to be a crypto key and comes with working Linux code — but the license prohibits Greg from using the USB device as freely as he would like. This puts Greg back in the position of reverse-engineering a USB protocol. In the same way that Windows-running-atop-Linux-in-VMWare provides a way to monitor USB communication that takes place in usbfs, adding usbfs logging to Linux helps to see what commands are being sent from the too-restrictive Linux library for this USB device.
If you understood that last sentence, congratulations for paying such close attention. 🙂 To continue, Greg walks the reader through a patch to the kernel to enable kernel-based logging of any USB communication through usbfs. He even adds a variable (controllable through sysfs) so that users can turn this USB logging on and off at will.
At this point (looking on the web, not in the kernel source), I noticed several reports of additional USB logging in Linux. There was Greg’s article. There’s usbmon, which is “a facility in kernel which is used to collect traces of I/O on the USB bus.” I noticed a patch by Paolo Abeni to add binary dumps to usbmon. Both usbmon and Paolo’s patch utilize debugfs, which is another Greg Kroah-Hartman invention to allow reading/writing of data to user space, especially debugging/binary data. As Greg puts it, “one line of code and you have a variable that can be read and written to from userspace.” And Eric Preston evidently added binary dumping of USB data to Linux as well, and then started a USB protocol dissector to view USB communication in ethereal/Wireshark, which normally is used to sniff on network communication.
Now we’ve gotten a lot of background, so we’re ready to look at an example actually monitoring USB communication in Linux. The best write-up I’ve seen is this one on USB snooping on Linux. It’s a little over a year old, but check out one of the comments:
The cool thing I have spotted is that the debugfs and usbmon module is already present under ubuntu. You will not need to compile or configure the kernel, just mount the debugfs, load the usbmon module, and the usbmon directory should appear under the /sys/kernel/debug directory.
That means that a stock Ubuntu 7.10 (Gutsy Gibbon) install can just run these commands:
sudo mount -t debugfs none_debugs /sys/kernel/debug
sudo modprobe usbmon
ls -l /sys/kernel/debug/usbmon/
total 0
-rw——- 1 root root 0 2008-02-17 00:59 0s
-rw——- 1 root root 0 2008-02-17 00:59 0t
-rw——- 1 root root 0 2008-02-17 00:59 0u
-rw——- 1 root root 0 2008-02-17 00:59 1s
-rw——- 1 root root 0 2008-02-17 00:59 1t
-rw——- 1 root root 0 2008-02-17 00:59 1u
-rw——- 1 root root 0 2008-02-17 00:59 2s
-rw——- 1 root root 0 2008-02-17 00:59 2t
-rw——- 1 root root 0 2008-02-17 00:59 2u
After that, you’re ready to cat those files, exercise the USB device, and observe the resulting USB traces to figure out what commands and data passed back and forth. In case you’re wondering, the filenames seem to be a number (0,1,2) followed by a letter (s,t,u). According to the usbmon documentation, the number corresponds to the bus numbers of the USB devices. The documentation also mentions that the ‘u’ files are a superset of the ‘t’ files with more detailed information. I don’t know what the ‘s’ files are.
Just as an aside, it looks like /proc/bus/usb/ is deprecated in Ubuntu 7.10 and is being replaced with /dev/bus/usb. Unfortunately, that breaks a few programs (usbview, virtualbox, and qemu). Instead of usbview, you can use lsusb to find the particulars of a specific USB device. Unfortunately, it sounds like /proc/bus/usb/devices is going away entirely, which is a shame because the file was easy-to-read for regular users. The bug report I linked to gives a workaround if you really want that file.