An Overview of Linux USB

Learn some of the basics of the USB subsystem, including how URBs work and what kind of host controllers are available.


The USB subsystem is based on message passing transactions. The messages are
called URBs, which stands for USB request block. URBs are sent by calling
the usb_submit_urb method, struct urb *urb, int
mem_flags
). This is an asynchronous call, and it returns
immediately. The URB is put in a queue, and later, it reaches a
completion handler. The completion handler is a member of the URB structure
called complete, a pointer to a function in the URB struct. In the completion
handler, you can check urb -> status to see if any errors have been
detected.

To cancel pending requests, use usb_unlink_urb(). URBs
are allocated by calling usb_alloc_urb(), and they are freed with a call to
usb_free_urb(). Three helper methods are available to help fill URBs:
usb_fill_control_urb(), usb_fill_bulk_urb and usb_fill_int_urb.

The URB struct resides in include/usb/usb.h, which is one of the two most
important headers that define the USB interface. The second is
include/linux/usb_ch9.h. Another little file also is called
usb.h and can be found in usb/core, but it is not important in this context.

The header file called usb_ch9.h hold constants and structures for USB.
The name comes from chapter 9 of the USB 2.0 specification. Currently,
there are two specifications for USB, 2.0 and 1.1. USB 2.0 operates at
high speed, defined as 60MB/s (480Mb/s), which is 40 times faster than
USB full speed. USB 1.1 operates either at full speed, which is 1.5MB/s
(12Mb/s), or at low speed, which is 1.5Mb/s. When you connect high speed
devices to USB 1.1 systems, they operate at USB 1.1 speeds.

The USB_SPEED_LOW, USB_SPEED_FULL and USB_SPEED_HIGH constants are
defined in usb_ch9.h. The constants are encountered here and there
in the USB sources in the kernel.

Four types of transfers exist: control transfers, bulk transfers, interrupt
transfers, and high speed isochronous (ISO) transfers. USB Webcams
usually use ISO transfer, and you rarely find use of bulk transfers
there.
USB Host Controllers
In the kernel source tree, under /drivers/usb/host, you find five types of
USB host controllers defined:

  1. EHCI for USB2.0, EHCI stands for enhanced host
    controller interface.
  2. OHCI, or OpenHCI, the open host controller
    interface. According to /usb/host/Kconfig, OHCI "does more in hardware
    than Intel's UHCI specification" does. For example, sending a 4KB buffer
    takes one TD with OHCI, covering 64+ packets; with UHCI, each packet
    takes one TD. In addition, OHCI has separate schedules for control, bulk
    and periodic transfers, whereas UHCI has only one.
  3. UHCI, the universal host controller interface, originated
    from Intel. Boards with Intel PCI chipsets usually use this
    standard.
  4. SL811 host controller, manufactured by Cypress. It has
    256MB of internal SRAM buffer.
  5. SA-1111 host controller, the drivers for these
    controllers are located under /drivers/usb/host. They sometimes are
    referred to as HCD, which stands for host controller
    driver.

So what do we have in the USB initialization? Let's take a look at
/drivers/usb/core/usb.c for that information. We call six initialization
routines, but only three of them are part of the sub-subsystem.

  1. bus_register(&usb_bus_type): the bus_register() method is
    not a part of the USB subsystem. It's a general bus method, and its
    implementation is found /drivers/base/bus.c.
  2. usb_host_init(): this calls class_register(), but it is
    not a part of the USB subsystem. Its implementation is stored
    in /drivers/base/class.c.
  3. usb_major_init(): this calls register_chre_dev() as well
    as devfs_mk_dir("usb") and class_register(). The major number of USB is
    180. All entries under /dev/usb have major number 180, except /dev/ttyUSB*,
    which have major number 188. The call to class_register() is relatively
    new and did not exist in the 2.4 kernel.
  4. usbfs_init(): in most distros, the USBFS--which also is
    called usbdevfs--is mounted under /proc/bus. Of course, this can be
    changed by issuing umount and then
    mount on a different mounting point or by changing
    /etc/fstab.USBFS is a filesystem that in some ways resembles ordinary
    filesystems, such as ext3 or XFS. They resemble one another in that you
    call register_filesystem(), in /drivers/usb/core/inode.c, in order to register the filesystem,
    and you pass a pointer to file_system_type. Most of the relevant code
    for the USBFS is stored in usb/core/inode.c, where you can find methods
    such as usbfs_fill_super(), which usually is found in super.c in other
    filesystems. You also can find file operations there, including
    default_read_file() and default_write_file().USBFS is responsible for creating and updating the devices file,
    /proc/bus/usb/devices. The devices file is updated dynamically; if you
    insert a Webcam or any other USB device and run cat
    /proc/bus/usb/devices
    , you will find that some configuration
    entries have been added to the devices file. Similarly, if you remove
    the Webcam and run cat /proc/bus/usb/devices, these
    devices are removed from the devices file.Creating the devices file eventually happens by calling regular
    filesystem methods from dcache.c.
  5. usb_hub_init(): creates a kernel daemon thread named
    khubd; its implementation is in /drivers/usb/core/hub.c. The khubd thread
    is responsible for configuring devices.
  6. driver_register(): this method is not a part of the USB
    subsystem. Its implementation can be found in
    /drivers/base/driver.c

Plugging and Unplugging a USB Device
The nine mandatory ingredients of the USBcore are: usb.c, hub.c, hcd.c, urb.c,
message.c, config.c, file.c, buffer.c and sysfs.c. If, when configuring the kernel,
you set CONFIG_USB_DEVICEFS to yes, add three more items to the USBcore
list: devio.c, inode.c and devices.c. inode.c implements the USBFS, and
it makes a call to register_filesystem.

khubd is a daemon thread. After we create it, we call daemonize(),
which blocks all signals. See daemonize() implementation in
/kernel/exit.c for more details. We want to be able to send a kill
signal (SIGKILL) when cleaning up, so we enable this by calling allow_signal(SIGKILL)
immediately after creating khubd.

Usually, when you run ps -aux and look at the khubd process,
you see that it is sleeping, denoted by the letter S. When we plug a USB device
into the USB port, the hardware layer initiates an interrupt; we reach the hub_irq() method.
The hub data, represented by struct usb_hub, is passed to the hub_irq() method
as part of the URB, the context member of struct urb.

A global list of hub events, called hub_event_list, is available. If
this list is empty, we add an event to this list, so that the khubd thread
can handle it. We also call wake_up(&khubd_wait), as khubd is in waiting status.
Waking up causes us to call hub_events(). We also reach the host
controller IRQ. For example, when I am working with OHCI, I reach ohci_irq()).
The hub driver writers admit that restarting the list every time to
avoid creating a deadlock by deleting hubs downstream from this current hub
is not the most efficient method, but it is safe.

When we unplug a USB device out from it USB port, the process described
above is repeated until we reach hub_events(). There we call the
hub_port_connect_change() method, which is implemented in hub.c. The second
parameter of this method is the port number, so this method disconnects
all existing devices on this port by calling usb_disconnect().
usb_disconnect(struct usb_device **pdev) also is a USBcore method implemented
in usb.c.

The usb_disconnect() calls usb_disable_device() which disables all the
endpoints for a USB device. It also removes that USB device endpoints from
/proc/bus/usb/devices by calling usbfs_remove_device(dev). Notice,
however, that hub_disconnect() is not called during this process. hub_disconnect()
is called when we perform rmmod ohci_hcd, for
example, when working with OHCI. It also is called in the probing
process at bootime; more specifically, hub_probe() calls hub_disconnect()
as it's last step before returning. The entries under /sys/usb/usb/drivers/hub
are not removed after unplugging a device. They are removed, for example, after
rmmod ohci_hcd is executed, assuming that you're working
with ohci_hcd.
Tools and Libraries
When working with the USB subsystem, I found some tools and libraries to
be especially helpful. USBView is a GTK+ 1.2-based tool written by Greg
Kroah-Hartman that enables you to see the characteristics of the USB devices.
This tool displays the topography of the devices plugged into the USB bus on
a Linux machine. When plugging and unplugging the USB device, the display
is updated and refreshed in real time. The source code also is available.

Other tools and libraries that might help include UsbSnoop, which is some
kind of USB sniffer that runs only on Windows. A new patch called
USBMon, written by Pete Zaitcev, is available that enables you to monitor
USB traffic. Finally, the libusb project is trying to create a library
that can be used by user-level applications to access USB devices regardless
of OS.
USB Mass Storage Driver for Linux
I end this article with a brief discussion of the USB Mass Storage Driver.
This driver is intended for mass storage USB devices, including USB disks and
USB DiskOnKeys. What follows below is relaxant to USB DiskOnKeys, but I assume
USB disks also behave more or less the same.

To mount a DiskOnKey, you first should create a mounting point, let's
say /mnt/dok, and then run:

mount /dev/sda /mnt/dok

The code for the USB Mass Storage Driver resides, naturally, under
drivers/usb/storage. The module name is usb-storage.ko; it uses
SCSI emulation.

The us_data structure, from storage/usb.h, probably is the most important
struct in storage mass storage. The protocol we use is transparent SCSI.
The transport layer is bulk, which corresponds to US_PR_BULK in usb/transport.h.

The use of SCSI emulation appears also in ATAPI devices, such as CD-RW devices.
It is a good question to ask why we use this emulation at all. Why not
use the IDE interface? I personally wonder what the reason is. To me, it does not
seem to be related to the fact that IDE disks are not hot plugged while USB disk can be
hot plugged.

The usb_stor_control_thread() is a daemon thread that controls the USB device. It
adds the PF_NOFREEZE flag to the current process. Aside from this module, use of
PF_NOFREEZE appears in only two other places under the drivers subtree
of the Linux kernel source: in block/loop.c in the loop_thread(void *data) method and
in scsi/scsi_error.c in scsi_error_handler(void *data). The PF_NOFREEZE
flag is used for Swsusp, which stands for software suspend in Linux and
is the equivalent of Windows' hibernate mode.
Note
The code cited in this article is from the USB layer in the
2.67 kernel; it has changed little in newer versions.
Resources
The USB Linux Portal

Useful Information about
Linux Device Drivers

The
linux-usb-users Mailing List Archive

The
linux-usb-developer Mailing List Archive

The
UHCI Spec

The
SL811 Host Controller

The
SA-1111 Host Controller

USBView

usbsnoop

A Linux Kernel Mailing
list (lkml) Thread About the New USBMon Patch

The GNU/Linux usbnet
Driver, by David Brownell

libusb

"Modifying a
Dynamic Library Without Changing the Source Code"
. An
Linux Journal by Greg Kroah-Hartman in which he
explains how to use the libusb.

USB Mass
Storage Driver for Linux
. Take into account, however, that this
site was updated last in July 2002.

Software Suspend for
Linux

Rami Rosen is a software engineer who recently has been working on
Linux software for a startup company that develops videoconference and
VoIP solutions. He is a devoted Linux kernel hacker, and he also loves
music, reading and running.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Command to Disable EHCI

indra's picture

Hello there,

I'm very new to linux and I want to know the command to disable EHCI (USB2)?
Can anyone tell me how?

1st - MANY THANKS - 2nd - I still can't access my usb ports!

Lazer's picture

I have been using my HP pavilion ze5300 laptop for two years under
SUSE Linux. Everything has worked perfect under the 2.4 kernel.

Since I went to the 2.6 kernel no matter which flavor of SUSE
(Pro, NLD or SLES) I have not been able to access any usb device!!!

CAN YOU PLEASE HELP - I AM GOING CRAZY WITHOUT MY USB PORTS WORKING
WITH MY TREO PHONE,PRINTER,FLASH DRIVE !!!

MANY THANKS IN ADVANCE.... Lazer

typo?

Dan's picture

there is a reference to function register_chre_dev() in the article, but i can't seem to find a reference to it in the linux kernel. i also can't find a reference to it on google, save for this article.

what is the function supposed to be?

the function name is register

Anonymous's picture

the function name is register_chrdev.

Device Controller API

Anonymous's picture

Is there some documentation regarding USB driver usage when Linux is being used on an embedded system and is behaving as a device ( not host ). Does LInux provide an OS level API or does the interaction have to be with the driver API

Bootable USB Flash drive with Linux, Busybox, httpd, sshd

Wiwat Tara's picture

I have built a Bootable Linux system for a USB Flash Drive using GRUB, Busybox and Linux kernel 2.6.10 (with a patch).

It works either your x86 system allows "boot from usb" or specify grub.conf on your normal Linux to boot off USB (kernel and root filesystem.)

It boots Linux 2.6.10 kernel with Busybox login, httpd, sshd with r/w partion as well.

Here is my work if you are intertested.

http://ohhohe.tripod.com/files/linux_usb_flashdrive.pdf

Feather Linux

Anonymous's picture

Have you seen this distro for USB Flash drives:

http://featherlinux.berlios.de/usb-instructions.htm

It's really nice.

USBMon vs. usbmon

Pete Zaitcev's picture

The the snooping facility in 2.6.11 is called "usbmon" in lowercase. USBMon is a GUI application written by David Harding, which now works in concert with usbmon. They are not the same thing. It is possible to use usbmon without USBMon.

Re: USBMon vs. usbmon

Anonymous's picture

Well, at least it's not confusing.

White Paper
Fabric-Based Computing Enables Optimized Hyperscale Data Centers

Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.

Learn More

Sponsored by AMD

White Paper
Red Hat White Paper: Using an Open Source Framework to Catch the Bad Guy

Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6

Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.

Learn more about catching the bad guy in this free white paper.

Learn More

Sponsored by DLT Solutions