Writing a Real Driver—In User Space
Last time we discussed how to create a simple USB driver that controlled a USB LED device manufactured by Delcom Engineering [LJ, April 2004]. I would like to thank all of the readers who have given me feedback on the column. It even enabled one reader to write a driver now in the main kernel tree. I also would like to thank everyone who has given me ideas about what kinds of devices to write about in future columns, but please remember, let's try to cover simple devices. We don't have the room here to go over how to reverse engineer a streaming video camera that has about 12 different modes of operation.
At the end of the last column, I said it is simple to talk to a USB device from user space, without needing a custom kernel driver. Way back during the development of the original Linux USB code, a few developers recognized that it would be wise to allow user programs to get at the raw USB data in all devices in addition to controlling the device. To that end, the usbfs filesystem was created. It originally was called usbdevfs, but many people confused it with the devfs filesystem and all of the nasty baggage that filesystem brought on, so it was renamed usbfs.
Traditionally, usbfs is mounted in the /proc/bus/usb directory on your machine. In that main directory exists a file called devices and a directory for every different USB bus connected to the machine. Those bus directories are named with a number that corresponds to the number the kernel has given that particular USB bus. In each bus directory is a file for every different USB device connected to the bus. For example, a box that has six different USB buses and a few USB devices connected might look like this:
$ tree /proc/bus/usb/ /proc/bus/usb/ |-- 001 | `-- 001 |-- 002 | `-- 001 |-- 003 | `-- 001 |-- 004 | |-- 001 | |-- 002 | `-- 003 |-- 005 | `-- 001 |-- 006 | `-- 001 `-- devices
If you do not have any USB host controller drivers loaded, the main /proc/bus/usb/ directory should be empty.
The /proc/bus/usb/devices file contains a list of all USB devices attached at that moment in time. It also shows how the devices are connected to one another and a lot of other USB-specific information about each device. For details on how the data in this file should be interpreted, see the documentation in the kernel tree at Documentation/usb/proc_usb_info.txt. Programs such as usbview or usbtree use this file to show information about USB devices.
The files within the /proc/bus/usb/BBB/ directories, where BBB is the number of the USB bus, allow programs to talk directly to the different USB devices. The name of the files are the same number as the USB number assigned to the device: 001 for the first device, 002 for the second and so on. Do not rely on these numbers to be unique, as the USB subsystem reuses the numbers when devices are removed and added. If device 003 is removed and another, different device is added, it gets the 003 number.
If you read from the device file, the raw USB descriptor is returned—first the USB device descriptor and then the different configuration descriptors. For a detailed description of what format these descriptors are in and what all of the data means, see the USB specification, which is available for download at the USB Developers Web site (www.usb.org/developers).
The device file also supports a wide range of ioctl calls that allows programs to send and receive USB data from the device. These ioctls and the structures needed for the ioctls are described in the kernel file include/linux/usbdevice_fs.h.
Armed with these ioctls, the structures defined in this header file and a copy of the USB specification, we are set to write a user-space program to talk to our device. But do we really want to do this? Wouldn't it be great if someone wrote a library on top of this interface that would enable us to write sane programs? Luckily, a group of developers has created such a library, allowing programmers to ignore the ioctl mess that usbfs uses. This library is called libusb.
libusb is a library that works on a number of different operating systems: Linux, the various BSDs and Mac OS X. It allows programs to be written in a portable manner and yet still control USB devices on vastly different operating systems. Using this library lets us create a program to control the USB LED device. libusb can be downloaded from libusb.sf.net if it is not included in your Linux distribution.
The first thing any libusb program must do is initialize the library and have it scan all USB buses for all USB devices. This is done with the following three function calls:
usb_init(); usb_find_busses(); usb_find_devices();
After the call is complete, the program needs to find a USB device that matches the desired description. As all USB devices have unique vendor and product identification values, it usually is easiest to look for these values. As we remember from the kernel driver we created last time, the USB LED device has the following vendor and product values:
#define LED_VENDOR_ID 0x0fc5 #define LED_PRODUCT_ID 0x1223
With this information, the code to find this device using libusb is the following:
for (usb_bus = usb_busses; usb_bus;
usb_bus = usb_bus->next) {
for (dev = usb_bus->devices; dev;
dev = dev->next) {
if ((dev->descriptor.idVendor ==
LED_VENDOR_ID) &&
(dev->descriptor.idProduct ==
LED_PRODUCT_ID))
return dev;
}
}
return NULL;
If the device is found in the system, a pointer to it is returned, otherwise NULL is returned. This pointer is of type struct usb_device. After this structure is found, the USB device must be opened and a handle must be created by libusb for the program to communicate with the device. This is done with the following simple code:
usb_handle = usb_open(usb_dev);
if (usb_handle == NULL) {
fprintf(stderr,
"Not able to claim the USB device\n");
goto exit;
}
This usb_handle variable is of type struct usb_dev_handle, and it is what libusb uses to determine with which USB device it should communicate. This handle is all that is needed to set up our USB device to be ready to communicate with it.
When the program is finished with the USB device, a call to usb_close(usb_handle); is all that is necessary to clean up all of our structures and notify libusb that the device is no longer needed.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.
Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.
Sponsored by ActiveState
| Non-Linux FOSS: libnotify, OS X Style | Jun 18, 2013 |
| Containers—Not Virtual Machines—Are the Future Cloud | Jun 17, 2013 |
| Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer | Jun 12, 2013 |
| Weechat, Irssi's Little Brother | Jun 11, 2013 |
| One Tail Just Isn't Enough | Jun 07, 2013 |
| Introduction to MapReduce with Hadoop on Linux | Jun 05, 2013 |
- Containers—Not Virtual Machines—Are the Future Cloud
- Non-Linux FOSS: libnotify, OS X Style
- Linux Systems Administrator
- Validate an E-Mail Address with PHP, the Right Way
- Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
- Senior Perl Developer
- Technical Support Rep
- UX Designer
- Introduction to MapReduce with Hadoop on Linux
- RSS Feeds
- One advantage with VMs
39 min 15 sec ago - about info
1 hour 12 min ago - info
1 hour 13 min ago - info
1 hour 14 min ago - info
1 hour 16 min ago - info
1 hour 17 min ago - abut info
1 hour 19 min ago - info
1 hour 20 min ago - info
1 hour 21 min ago - info
1 hour 22 min ago
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




Comments
How to create device entry under /dev in rootfs
Hi,
I am facing a issue, while creating /dev entry for LCD backlight driver.
I am using following functions for doing the same.
1) alloc_chrdev_region(&bl->bdev, 0, 1, BIHP_BL_DEVICE_NAME);
2) cdev_init(&bl->cdev, &bl_fops);
3) cdev_add(&bl->cdev, bl->bdev, 1);
Compilation is done properly, If I check /dev entry for backlight there it is showing nothing.
Please let me know, Am I doing any thing wrong?
Kind Regards,
Santhosh Reddy.P
Check /proc/devices
The device name (BIHP_BL_DEVICE_NAME) you specify in alloc_chrdev_region() puts an entry in /proc/devices not /dev. You create the /dev file with mknod.
Mitch Frazier is an Associate Editor for Linux Journal.
/proc/bus/usb deprecated
Just FYI /proc/bus/usb has been deprecated for a while and in fact is no longer mounted by default on recent Linux distros. The new location is /dev/bus/usb.
libusb-1.0.2
I've been trying to figure out how to do an isochronous read but I'm not having any luck. Could you please outline the sequence of steps to accomplish this. I'm using libusb_fill_iso_transfer () followed by libusb_submit_transfer () but this hangs up inside libusb. I'm suspicious that libusb is incomplete since I don't see any way of specifying the interval.
Also, I need to get at the manufacturers name string, but all I can find is an index (iManufacturer) in the device descriptor. There should be an access function.
So far I've been able to open this device, detach the kernel driver and claim the interface.
The device has a vendorId=18f5 and a productId=1000 (yes, it's in the Linux list). The device contains 2 joysticks and 16 switches (it's not a gaming device), I need to read the raw data so that I can extract the individual components. I have the memory map. Using usbviewer I found one endpoint at 0x81, the transfer size is 12 bytes and the interval is 5ms.
Hurst
access data from USB using c++
how can i access data from USB using c++ code, libusb1.0, in linux.
Some questions.
Hello, it's a very nice posting and great help for newbie like me.
I'm trying to implement a usb driver that enables a programmer can write a program to communicate with a usb device. But your advice seems not working for me because our device has API that communicate with the device and I just want the api can initialize the device and programmers don't have to care about it.
Could you give me any advice on that?
Also, I'm confused about the header file you included in the program. It has usb.h instead of libusb.h. is it something different from the libusb.h or you just wrote another header that refers libusb.h?
Thanks,
USBFS IOCTLS
Hi ,
This is a very interesting article . Is the documentation for using USBFS IOCTL's documented .
I wanted to issue basic USB String Descriptor to a device .
Help is appreciated
Thanks
What are the usb_control_msg values?
Hi Greg -
Thanks for the great article. It's been a big help in writing a program to talk to a little communications board that I'm working with.
I have a question about the usb_control_msg() function, and I can't find any documentation on it (no man page, even on the Google?).
What are requesttype, request, value, and index for, exactly? Your program has requesttype 0x000000c8 (not sure where this is defined/how you chose it), request 0x00000012 (again, not sure how you decided this was the option to use), value (0x02 * 0x100) + 0x0a, index 0xff & (~color). It seems a little odd to me, wouldn't the request type/etc simply be part of the usb packet header and the data would be which pins you're setting? Probably my device is a little more complicated :).
I've been using SnoopyPro to sniff my device (i have a program for windows that interfaces with it correctly) and all the communication with the device is using Function "BULK_OR_INTERRUPT_TRANSFER" (0x09), so I'm guessing this would be my request_type? or my request? My device receives data via the buffer variable, so buffer and length are a no brainer (I know what these values need to be), I'm just not sure about these header-y things. If you have any idea or know a good place for documentation, toss it my way.
Thanks a ton,
Reid
yeah! What are the usb_control_msg values?
Somebody can you tell us?
According SnoopyPro for my device i got something like this:
-----------
URB Header (length: 80)
SequenceNumber: 10
Function: 001b (CLASS_INTERFACE)
PipeHandle: 00000000
SetupPacket:
0000: 22 01 00 03 00 00 00 00
bmRequestType: 22
DIR: Host-To-Device
TYPE: Class
RECIPIENT: Endpoint
bRequest: 01
No TransferBuffer
-----------
I guess that bmRequestType:22 is the 2nd parameter, bRequest:01 is the 3rd. But, what about the 'value' and 'index' parameters?
If you read the line-> 0000: 22 01 00 03 00 00 00 00 it's the command sent to the device .. but how can i put this into the usb_control_msg function?
Thanks!
PS: I don't speak english ... sorry
Errors while compilling
Anybody could help me?
I found some errors wihle I tried do compile this example:
g++ -c -o usb.o usb.cc
usb.cc: In function ‘void change_color(usb_dev_handle*, unsigned char)’:
usb.cc:24: error: ‘usb_control_msg’ was not declared in this scope
usb.cc: In function ‘usb_device* device_init()’:
usb.cc:30: error: ‘usb_init’ was not declared in this scope
usb.cc:31: error: ‘usb_find_busses’ was not declared in this scope
usb.cc:32: error: ‘usb_find_devices’ was not declared in this scope
usb.cc:33: error: ‘usb_busses’ was not declared in this scope
usb.cc:35: error: invalid use of undefined type ‘struct usb_bus’
usb.cc:28: error: forward declaration of ‘struct usb_bus’
usb.cc:36: error: invalid use of undefined type ‘struct usb_bus’
usb.cc:28: error: forward declaration of ‘struct usb_bus’
usb.cc:38: error: invalid use of undefined type ‘struct usb_device’
usb.cc:26: error: forward declaration of ‘struct usb_device’
usb.cc:39: error: invalid use of undefined type ‘struct usb_device’
usb.cc:26: error: forward declaration of ‘struct usb_device’
usb.cc:41: error: invalid use of undefined type ‘struct usb_device’
usb.cc:26: error: forward declaration of ‘struct usb_device’
usb.cc: In function ‘int main(int, char**)’:
usb.cc:60: error: ‘usb_open’ was not declared in this scope
usb.cc:63: error: expected primary-expression before ‘goto’
usb.cc:89: error: ‘usb_close’ was not declared in this scope
expected primary-expression before "goto"
Same problem when I try to use goto in the place like these
if(goto location);
OR
i!=j?goto location:exit;
If you know the solution or why is this happening plz mail me.
Thnks,
Daniel
Errors while compilling
Hi Felipe,
Try this:
locate libusb
/usr/lib/libusbhid.a
/usr/lib/libusbhid.so.3.0
/usr/lib/libusbhid_p.a
/usr/lib/libusbhid_pic.a
/usr/local/bin/libusb-config
/usr/local/lib/libusb.a
/usr/local/lib/libusb.so.8.2
/usr/local/lib/libusbpp.a
/usr/local/lib/libusbpp.so.9.0
/var/db/pkg/libusb-0.1.10ap1
/var/db/pkg/libusb-0.1.10ap1/+CONTENTS
/var/db/pkg/libusb-0.1.10ap1/+DESC
/var/db/pkg/libusb-0.1.10ap1/+REQUIRED_BY
gcc -o driver driver.c -L/usr/local/lib -lusb
It compiles without problems on OpenBSD 4.1, just remember to force library path to libusb to compile.
HELP ME ???
Hi,
I wanted to write just a simple driver for my usb-mass-storage (memory stick).
All I want to do is to flash (On/Off) the led on the device. It is only one led, I changed the LED_VENDOR_ID and LED_PRODUCT_ID Everything works fine, except that this usb_control_msg() doesnt work for this device :(!
Can someone help me with this? All I want is to switch this Led On and Off! Nothing more :).
Do I have to use another function? Is there a function that can manage to do this(put this only Led on)?
I hope u can help me with this.
Thank you
Little mistake in the code
In the program code appears:
if (usb_handle == NULL) {
fprintf(stderr,
goto exit;
}
I think this is a block that can be deleted because the error check is also done in the next block.
¡Nice article!
Bad code...
Hmm, goto's are bad anywhere.
Also doesn't your control message write 8 bytes to a random location (dummy isn't initialised)?
And you don't use usb_claim_interface() anywhere. The doc's say this "Must be called!" I'm not entirely sure what an interface is yet though. libusb has terrible documentation. It is also the best example of why C++ is better than C that I've ever seen.
Re: Writing a Real Driver
hello,
I just want to ask for some links to more information about USB in general, how to implement USB in Self build devices,
An overview, how USB (and pehaps also the serial and parallel interface) are implemented in Gnu/Linux and also BSD-Unix.
I'm an Engineer and it was easy to send some bytes to a device in the Dos Area - continued in Win9x. How can I do it - as easy as possible in Linux, especialy if new computers only have USB - this is the Future if we believe Intel
Greatings
D. Schneider
Re: Writing a Real Driver
hello,
this is in your example code:
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 device
");
goto exit;
}
Sorry for the request but the libusb developer manual say to call usb_init() and usb_claim_device() (for claim), before any operation with USB device...
There are step by step example to respect correct order?
Greatings
R.LOBERTO
ioctl for massive storage device
Hi,
I want to access the massive storage device (memory stick) using ioctl instead of libusb. Can you recommend a reference for this purpose?
I tried to do the work but was not successful. The sequence of actions I did is as following:
/*open the device*/
fd = open(file, O_RDWR);
/*reset the device*/
ioctl(fd, USBDEVFS_RESET, NULL);
close(fd);
fd = open(file, O_RDWR);
/*configure the device*/
ioctl(fd, USBDEVFS_SETCONFIGURATION, &configuration);
/*claim the interface*/
ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
/*read data via the bulk endpoint*/
ioctl(fd, USBDEVFS_BULK, &bulk);
All steps successed until it failed at the last step.
Regards,
Jing