We would like to show you a description here but the site won’t allow us.
The Linux USB subsystem has grown from supporting only two differenttypes of devices in the 2.2.7 kernel (mice and keyboards), to over 20different types of devices in the 2.4 kernel. Linux currently supportsalmost all USB class devices (standard types of devices like keyboards,mice, modems, printers and speakers) and an ever-growing number ofvendor-specific devices (such as USB to serial converters, digitalcameras, Ethernet devices and MP3 players). For a full list of thedifferent USB devices currently supported, see Resources.
The remaining kinds of USB devices that do not have support on Linux arealmost all vendor-specific devices. Each vendor decides to implement acustom protocol to talk to their device, so a custom driver usuallyneeds to be created. Some vendors are open with their USB protocols andhelp with the creation of Linux drivers, while others do not publishthem, and developers are forced to reverse-engineer. See Resources forsome links to handy reverse-engineering tools.
Because each different protocol causes a new driver to be created, Ihave written a generic USB driver skeleton, modelled after thepci-skeleton.c file in the kernel source tree upon which many PCInetwork drivers have been based. This USB skeleton can be found atdrivers/usb/usb-skeleton.c in the kernel source tree. In this article Iwill walk through the basics of the skeleton driver, explaining thedifferent pieces and what needs to be done to customize it to yourspecific device.
If you are going to write a Linux USB driver, please become familiarwith the USB protocol specification. It can be found, along with manyother useful documents, at the USB home page (see Resources). Anexcellent introduction to the Linux USB subsystem can be found at theUSB Working Devices List (see Resources). It explains how the Linux USBsubsystem is structured and introduces the reader to the concept of USBurbs (USB Request Blocks), which are essential to USB drivers.
The first thing a Linux USB driver needs to do is register itself withthe Linux USB subsystem, giving it some information about which devicesthe driver supports and which functions to call when a device supportedby the driver is inserted or removed from the system. All of thisinformation is passed to the USB subsystem in the
usb_driverstructure. The skeleton driver declares a
The variable name is a string that describes the driver. It is used ininformational messages printed to the system log. The probe anddisconnect function pointers are called when a device that matches theinformation provided in the
id_table variable is either seen orremoved.
The fops and minor variables are optional. Most USB drivers hook intoanother kernel subsystem, such as the SCSI, network or TTY subsystem.These types of drivers register themselves with the other kernelsubsystem, and any user-space interactions are provided through thatinterface. But for drivers that do not have a matching kernel subsystem,such as MP3 players or scanners, a method of interacting with user spaceis needed. The USB subsystem provides a way to register a minor devicenumber and a set of
file_operations function pointers that enablethis user-space interaction. The skeleton driver needs this kind ofinterface, so it provides a minor starting number and a pointer to its
The USB driver is then registered with a call to
usb_register(),usually in the driver’s init function, as shown here:
When the driver is unloaded from the system, it needs to deregisteritself with the USB subsystem. This is done with the
To enable the linux-hotplug system to load the driver automatically whenthe device is plugged in, you need to create a
MODULE_DEVICE_TABLE.The following code tells the hotplug scripts that this module supports asingle device with a specific vendor and product ID:
There are other macros that can be used in describing a struct
usb_device_id for drivers that support a whole class of USBdrivers. See usb.h for more information on this.
When a device is plugged into the USB bus that matches the device IDpattern that your driver registered with the USB core, the probefunction is called. The
usb_device structure, interface number andthe interface ID are passed to the function:
The driver now needs to verify that this device is actually one that itcan accept. If so, it returns 0. If not, or if any error occurs duringinitialization, an errorcode (such as
-ENODEV) isreturned from the probe function.
In the skeleton driver, we determine what end points are marked asbulk-in and bulk-out. We create buffers to hold the data that will besent and received from the device, and a USB urb to write data to thedevice is initialized.
Conversely, when the device is removed from the USB bus, the disconnectfunction is called with the device pointer. The driver needs to cleanany private data that has been allocated at this time and to shut downany pending urbs that are in the USB system.
Now that the device is plugged into the system and the driver is boundto the device, any of the functions in the
file_operations structurethat were passed to the USB subsystem will be called from a user programtrying to talk to the device. The first function called will be open, asthe program tries to open the device for I/O. We increment our privateusage count and save a pointer to our internal structure in the filestructure. This is done so that future calls to file operations willenable the driver to determine which device the user is addressing. Allof this is done with the following code:
After the open function is called, the read and write functions arecalled to receive and send data to the device. In the
skel_writefunction, we receive a pointer to some data that the user wants to sendto the device and the size of the data. The function determines how muchdata it can send to the device based on the size of the write urb it hascreated (this size depends on the size of the bulk out end point thatthe device has). Then it copies the data from user space to kernelspace, points the urb to the data and submits the urb to the USBsubsystem. This can be seen in the following code:
When the write urb is filled up with the proper information using the
usb_fill_bulk_urb() function, we point the urb’s completion callbackto call our own
skel_write_bulk_callback function. This function iscalled when the urb is finished by the USB subsystem. The callbackfunction is called in interrupt context, so caution must be taken not todo very much processing at that time. Our implementation of
skel_write_bulk_callback merely reports if the urb was completedsuccessfully or not and then returns.
The read function works a bit differently from the write function inthat we do not use an urb to transfer data from the device to thedriver. Instead we call the
usb_bulk_msg() function, which can be usedto send or receive data from a device without having to create urbs andhandle urb completion callback functions. We call the
usb_bulk_msg()function, giving it a buffer into which to place any data received fromthe device and a timeout value. If the timeout period expires withoutreceiving any data from the device, the function will fail and return anerror message. This can be shown with the following code:
usb_bulk_msg() function can be very useful for doing single readsor writes to a device; however, if you need to read or write constantly toa device, it is recommended to set up your own urbs and submit them tothe USB subsystem.
When the user program releases the file handle that it has been using totalk to the device, the release function in the driver is called. Inthis function we decrement our private usage count and wait for possiblepending writes:
One of the more difficult problems that USB drivers must be able tohandle smoothly is the fact that the USB device may be removed from thesystem at any point in time, even if a program is currently talking toit. It needs to be able to shut down any current reads and writes andnotify the user-space programs that the device is no longer there. Thefollowing code (function
skel_delete) is an example of how to dothis:
If a program currently has an open handle to the device, we reset theflag
device_present. For every read, write, release and otherfunctions that expect a device to be present, the driver first checksthis flag to see if the device is still present. If not, it releasesthat the device has disappeared, and a
-ENODEV error is returned to theuser-space program. When the release function is eventually called, itdetermines if there is no device and if not, it does the cleanup thatthe
skel_disconnect function normally does if there are no open fileson the device (see Listing 5).
This usb-skeleton driver does not have any examples of interrupt orisochronous data being sent to or from the device. Interrupt data issent almost exactly as bulk data is, with a few minor exceptions.Isochronous data works differently with continuous streams of data beingsent to or from the device. The audio and video camera drivers are verygood examples of drivers that handle isochronous data and will be usefulif you also need to do this.
Writing Linux USB device drivers is not a difficult task as theusb-skeleton driver shows. This driver, combined with the other currentUSB drivers, should provide enough examples to help a beginning authorcreate a working driver in a minimal amount of time. The linux-usb-develmailing list archives also contain a lot of helpful information.
The Linux USB Project:http://www.linux-usb.org/
Linux Hotplug Project:http://linux-hotplug.sourceforge.net/
linux-usb Mailing List Archives:https://lore.kernel.org/linux-usb/
Programming Guide for Linux USB Device Drivers:https://lmu.web.psi.ch/docu/manuals/software_manuals/linux_sl/usb_linux_programming_guide.pdf
USB Home Page: https://www.usb.org