The arrival of USB support in Linux

These days, USB support is critical for the success of an operating system. Linux is now offering solid support in this arena, but it's not without its difficulties. Jim McIntyre shows you how to successfully support USB in Linux.

One of the more important advances made on recent versions of the Linux kernel is better support for the universal serial bus (USB). The widespread adoption of the USB standard by hardware manufacturers has placed a great demand on kernel developers to provide built-in support for both individual devices using the standard and for features that are shared across groups of devices such as printers, scanners, and USB cameras. In this Daily Drill Down, I will show how USB support has been implemented into the Linux kernel and how to make USB devices run. I will also discuss some open source tools that make USB device configuration much easier.

USB implementations
The USB standard establishes how computers and USB devices communicate with one another, but the chipset used on your computer actually determines how the connection is made to the processor. There are two common chipsets used to implement USB on your motherboard, and knowing which USB controller is used on your machine can be crucial to selecting the right kernel modules device support or compiling USB support into the kernel.

The Universal Host Controller Interface (UHCI), developed by Intel, is used on Intel motherboards and other boards using the VP and Apollo chipsets made by VIA. The Intel standard assigns X86-specific ports to their USB controllers

The Open Host Controller Interface (OHCI) is a standard developed by National Semiconductor, Compaq, and Microsoft, and is common on Power Macs and other non-Intel boards, such as Gigabyte boards. The OHCI standard assigns the USB controller to open memory space where it is visible to any system. If you need to know the implementation your system is using, try the following command:
/sbin/lspci -v

Look for output lines beginning with "USB Controller." The first line will identify whether the UHCI standard is being used on your system. If your system uses the UHCI standard, you will see a line beginning with "I/O ports at." Output lines that begin with "Memory at" indicate that the OHCI standard is being used.

There is also a third USB implementation emerging. Enhanced Host Controller Interface (EHCI), also known as USB 2.0, promises to transfer data up to 40 times faster (480 Mb/sec) than USB 1.0 (12 Mb/sec). The controllers for this standard are now entering the marketplace, but there are still very few devices that are able to take full advantage of this implementation. If your system uses a USB 2.0 controller, any USB 1.0 devices will still be compatible with the USB 2.0 standard.

Kernel module support for USB
Originally, Linux provided hardware support by including the code for device drivers with the kernel source code. Once the system was installed, the kernel quite often had to be recompiled to provide support for devices on a specific system. This meant that whenever a user installed or removed a particular device, or wanted to apply an updated driver, the whole kernel had to be rebuilt.

If the kernel has to be recompiled every time a new device is added to the system, the advantages of using USB devices are lost. To get around this problem, Linux now uses a modular kernel, which allows the Linux kernel to be compiled with only the most crucial bootstrap support. Support for peripheral devices may then be compiled into special files called kernel modules. Kernel modules can be loaded and removed without rebooting the system and without recompiling the kernel. The use of modules also allows for plug and play support.

Because so many types of hardware often share the same characteristics, different kernel modules can provide support for a wide variety of devices. The usbcore module, for example, provides USB support for many different USB devices; the usb-storage module uses some of the code from the SCSI-device support module to support USB-based storage devices as well as USB-card readers; and the input module provides support for USB controllers, in addition to several other types of devices.

You're probably used to seeing modules being loaded when Linux is booted on your system; the fact that these modules can be loaded automatically is great, but the ability to load modules manually will go a long way in helping you understand how Linux supports USB.

There are four Linux commands to become familiar with when working with kernel modules:
  • lsmod
    Lists the kernel modules currently loaded
  • insmod
    Inserts a specific kernel module
  • rmmod
    Removes a specific kernel module
  • modprobe
    Helps manage Linux modules

The usbcore module is required for USB hardware support. This module may be loaded separately with the command:
insmod usbcore

However, several other modules also use the usbcore module, so it is normally loaded by the modprobe command when commands such as modprobe usb-storage or modprobe printer are used. A better way to load the usbcore module is to run one of the following commands, depending on the chipset your system uses:
modprobe usb-ohci
modprobe usb-uhci

This will load the usbcore module and probe for any connected devices. Once one of these commands has run successfully, run the command:
cd /proc/bus/usb

There should be two files in this directory: the drivers file and the devices file. The drivers file lists the drivers for USB hardware that are presently compiled and loaded into the Linux kernel, and the devices file describes the USB devices connected to the system. The output from this file may look confusing at first, but there is a format that the information follows. The letter that the line begins with determines the type of information listed on each line. The following format is used for the devices file:
  • T: Topology
  • B: Bandwidth
  • D: Device descriptor info
  • P: Product ID information—a continuation of the device descriptor information
  • S: String descriptors—text strings used to describe the devices
  • C: Configuration Descriptor information
  • I: Interface descriptor
  • E: Endpoint descriptor

To view the drivers file, run the following command:
cat /proc/bus/usb/drivers

The output from the cat command should be similar to the following:
96-111: hiddev

The drivers file contains a list of drivers that can actually connect to a device. The hub driver connects the USB sockets on your USB controller to the motherboard. The usbdevfs driver discovers characteristics of a specific device and writes this information to the /proc/bus/usb/devices file. The numbers shown in the drivers are the minor device, or minor node, numbers associated with a specific device. Every device has two device numbers associated with it: the major number and the minor number. The major number is used to identify the driver used (for example, ide, SCSI, pci, USB, etc.), and the minor number is used so that the driver can see devices that are using the same or similar drivers as separate devices. USB serial ports are assigned major number 188 and minor numbers ranging from 0 to 255. Your kernel may limit the minor number to 63 or 127. The next command to run is:
cat /proc/bus/usb/devices

The above command will output the contents of the devices that will show you all USB devices connected to your system (but probably won't show drivers for all of these devices). If any of the lines beginning with the letter “I” have the text “Driver=(none),” then additional module support is required for the device to run correctly. Lines beginning with an “S” help you identify the driver required. The first device listed in this file is usually the root device. The root hub is actually the motherboard connection for the USB sockets. This device will appear whether any USB devices are connected or not. Other lines begin with “T” and are created for each device connected to the system.

Kernel modules may also be loaded by placing modprobe commands into startup scripts or by using the /sbin/hotplug command to load modules as the /proc filesystem is updated. On most Linux distributions, modules that are loaded automatically when the system is booted are listed in the /etc/modules.conf file.

Now, let's take a look at how to make specific types of USB devices work.

Connecting a USB printer
Use the following procedure to connect a USB printer to your system:
  1. Connect the printer to your system and run the command cat /proc/bus/usb/devices. The printer should be assigned to the device usblp. The USB printer module should now be available, which means you should be able to disconnect and reconnect the printer without receiving warning messages.
  2. If you want to connect a USB printer to your system while your parallel printer is still connected, run the following commands as root. First, create a new device named /dev/usb/lp0. This device is associated with major node 180 and minor node 0, and will be the first USB printer available. The file access rights to the device file are set to 660, which will allow root and members of the group lp to read from and write to the device file. This is accomplished with the command: mknod -m 660 c /dev/usb/lp0 180 0.
  3. Next, change the default group for this file to lp with the command: chgrp lp /dev/usb/lp0
  4. Once this is done, the /etc/printcap file must be edited to use the new printer. Open the printcap file in any text editor and change the following line:

Additional printers may be added to the system by repeating these procedures and incrementing the minor node number for each additional printer. Minor nodes from 0 to 15 may be used, allowing for up to 16 printers.

Connecting USB human interface devices
The term human interface device (HID) is a generic term used to describe any device providing user-generated input to the computer. This term is used to collectively describe mice, keyboards tablets, joysticks, and so on. To load the kernel module supporting these devices modules, use the command:
modprobe hid

There are other modules available, which provide support for specific devices such as the usbmouse and usbkdb modules, but the HID module provides support for a wider variety of devices and doesn't create much of a drain on your system resources. If you use the HID module, loading a device-specific module will only duplicate the work already being done by the HID module.

Once you’ve loaded the HID module, you do not have to configure the module to take input from a specific device because the HID module will read input from any HID.

Working with USB mice
To make a USB mouse work with Linux, the mousedev module is required. The mousedev module is used to translate input data from the HID and input modules into a format that Linux applications can use. If you already have a ps/2 mouse running on your system and want to make sure your new USB mouse works correctly before switching, run the following command as root:
mknod /dev/input/mice c13 63

When a mouse is plugged into the system, it will use major node 13 and share minor node 63 with any other mice attached to the system. When the real USB mouse is connected to the system, it will be assigned a minor node from 32 to 62. USB joysticks are assigned minor nodes 0 to 31, under /dev/input/js0, js1, and up. The /dev/input/mice character file actually emulates the more common /dev/psaux protocol. This allows you to switch from a ps/2 mouse to USB by simply changing the device line in the pointer section of the /etc/X11/XF86Config. Look for the following line in your XF86Config file:
Device     "/dev/input/psaux”

and change it to
Device      "/dev/input/mice"

Restart your X server, and the USB mouse should work correctly.

USB storage devices
Linux defines several different types of devices as USB storage devices. This category includes digital cameras, memory keys, SmartMedia cards, and Compact flash cards, in addition to standard storage devices such as Zip drives and CD drives. The usb-storage module used to provide support for these devices requires SCSI-driver extensions that are available only in the 2.4 kernels, so you won't be able to patch a 2.2 version to enable support for these devices. If your system already has an actual SCSI drive attached, that drive is probably found under /dev/sda. Any additional SCSI devices or pseudo-SCSI devices, such as USB storage devices, will be found under /dev/sdb, sdc, and so on. Many USB storage devices store data using the MSDOS FAT format. To access these devices under Linux, run the following command:
mount /dev/sdb -t vfat /mount-point

Then, run the command
ls /mount-point

to access data on the device The mount point may be given any name (for example, flash, cards, key). To make the process easier, add a line similar to the following to the /etc/fstab file:
/dev/sdb /mnt/cards vfat rw 0 0

To add device and driver information to the /proc/bus/usb/device and /driver files, add this line to /etc/fstab:
none /proc/usb usbdevfs devmode=0660 0 0

USB scanners
Linux assigns major node180 and minor nodes 48 to 63 to USB scanners. If USB scanner support is compiled into your kernel as a module, run the following command:
insmod scanner

This command will add the following line
48-63 usbscanner

to the /proc/bus/usb/drivers file. This driver is used by common applications, such as gPhoto, to provide communications between Linux and your scanner. If you want to use a USB scanner, you should use the most recent kernel available. Not all scanners will work just because there is a major and minor node assigned to them. A full discussion of USB scanners is beyond the scope of this article.

If you’re considering purchasing new USB hardware for your system, you should always make sure the device is Linux-compatible before buying. As a rule of thumb, hardware that has been on the market for less than six months may not yet have Linux drivers available. Always check the manufacturer’s Web site and other online sites to confirm driver availability.

Using USB configuration tools
Now that you’ve seen how USB support works manually, it’s time to take a look at a few of the tools that are currently available to automate the process, making USB configuration much easier.

Two of the more common USB support tools, usbmgr and Murasaki, run as user-mode daemons and automatically load USB modules and drivers. Here are some specifics on both of these tools:
  • usbmgr
    Usbmgr runs with 2.2 or 2.4 kernels and uses two text files, usbmgr.conf and preload.conf, to load modular support for a wide variety of USB devices. One advantage to using usbmgr is that vendor and product codes are supplied with the latest drivers available in the usbmgr.conf file. Even if you don’t use usbmgr to load modules, having this information readily available is very useful when a description of a USB is required for support with Linux.
  • Murasaki
    Murasaki requires a hotplug patch to run with kernels up to 2.2  and will run under 2.4 kernels with no modifications. Murasaki doesn't provide as complete a list of supported devices as usbmgr, but any device that works with usbmgr will work with Murasaki. These tools are well worth a look, as their configuration files provide very up-to-date support.

A more basic tool of USB automatic support is the jUSB, a Java-based interface that will scan your bus and report the status of all USB devices connected to your system.

The USB standard will continue to replace other methods of connecting peripheral devices to computers. Linux support for USB is rapidly growing, and knowledge of how USB is implemented in Linux has become an essential skill. In this article, I covered the basics of how Linux provides support for the USB standard and hardware. I discussed how Linux uses kernel modules to provide support for a wide variety of devices, the file used by administrators to manage USB devices, how specific types of devices are used with Linux, and some tools available to make USB support easier.

Other online resources