Writing a Simple USB Driver
This function starts out by setting all bits in the variable color to 1. Then, if any LEDs are to be enabled, it turns off only that specific bit. We then send a USB control message to the device to write that color value to the device.
It first seems odd that the tiny buffer variable, which is only 8-bytes long, is created with a call to kmalloc. Why not simply declare it on the stack and skip the overhead of dynamically allocating and then destroying it? This is done because some architectures that run Linux cannot send USB data created on the kernel stack, so all data that is to be sent to a USB device must be created dynamically.
With this kernel driver created, built and loaded, when the USB lamp device is plugged in, the driver is bound to it. All USB devices bound to this driver can be found in the sysfs directory for the driver:
$ tree /sys/bus/usb/drivers/usbled/ /sys/bus/usb/drivers/usbled/ `-- 4-1.4:1.0 -> ../../../../devices/pci0000:00/0000:00:0d.0/usb4/4-1/4-1.4/4-1.4:1.0
The file in that directory is a symlink back to the real location in the sysfs tree for that USB device. If we look into that directory we can see the files the driver has created for the LEDs:
$ tree /sys/bus/usb/drivers/usbled/4-1.4:1.0/ /sys/bus/usb/drivers/usbled/4-1.4:1.0/ |-- bAlternateSetting |-- bInterfaceClass |-- bInterfaceNumber |-- bInterfaceProtocol |-- bInterfaceSubClass |-- bNumEndpoints |-- blue |-- detach_state |-- green |-- iInterface |-- power | `-- state `-- red
Then, by writing either 0 or 1 to the blue, green and red files in that directory, the LEDs change color:
$ cd /sys/bus/usb/drivers/usbled/4-1.4:1.0/ $ cat green red blue 0 0 0 $ echo 1 > red [greg@duel 4-1.4:1.0]$ echo 1 > blue [greg@duel 4-1.4:1.0]$ cat green red blue 0 1 1
Now that we have created a simple kernel driver for this device, which can be seen in the 2.6 kernel tree at drivers/usb/misc/usbled.c or on the Linux Journal FTP site at (ftp.linuxjournal.com/pub/lj/listings/issue120/7353.tgz), is this really the best way to talk to the device? What about using something like usbfs or libusb to control the device from user space without any special device drivers? In my next column, I will show how to do this and provide some shell scripts to control the USB lamp devices plugged in to the system easily.
If you would like to see kernel drivers written for any other types of devices, within reason—I'm not going to try to write an NVIDIA video card driver from scratch—please let me know.
Thanks to Don Marti for bugging me to get this device working on Linux. Without his prodding it would have never gotten finished.
Greg Kroah-Hartman currently is the Linux kernel maintainer for a variety of different driver subsystems. He works for IBM, doing Linux kernel-related things, and can be reached at email@example.com.
Special Reports: DevOps
Have projects in development that need help? Have a great development operation in place that can ALWAYS be better? Regardless of where you are in your DevOps process, Linux Journal can help!
With deep focus on Collaborative Development, Continuous Testing and Release & Deployment, we offer here the DEFINITIVE DevOps for Dummies, a mobile Application Development Primer, advice & help from the experts, plus a host of other books, videos, podcasts and more. All free with a quick, one-time registration. Start browsing now...
- SUSE – “Will not diverge from its Open Source roots!”
- Dealing with Boundary Issues
- Vagrant Simplified
- Libreboot on an X60, Part I: the Setup
- System Status as SMS Text Messages
- Bluetooth Hacks
- October 2015 Issue of Linux Journal: Raspberry Pi
- Disney's Linux Light Bulbs (Not a "Luxo Jr." Reboot)
- New Products
- October 2015 Video Preview