Linux Kernel & Device Driver Programming

Ch 13 - USB Drivers

 

USB Basics


Linux USB Core


USB Device Overview


USB Endpoints


Linux USB Endpoint Structures

struct usb_host_endpoint {
   struct usb_endpoint_descriptor  desc;
   struct list_head                urb_list;
   void                            *hcpriv;
}
...
struct usb_endpoint_descriptor {
   __u8  bLength;
   __u8  bDescriptorType;
   __u8  bEndpointAddress; // see USB_ENDPOINT_DIR mask
   __u8  bmAttributes;     // see USG_ENDPOINT_XFERTYPE_MASK
   __le16 wMaxPacketSize;  // maximum that can be handled at once
   __u8  bInterval;        // milliseconds between interrupt requests
   // NOTE:  these two are _only_ in audio endpoints.
   // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof.
   __u8  bRefresh;
   __u8  bSynchAddress;
} __attribute__ ((packed));
...
#define USB_ENDPOINT_NUMBER_MASK        0x0f    /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK           0x80
#define USB_DIR_OUT                     0               /* to device */
#define USB_DIR_IN                      0x80            /* to host */
...
#define USB_ENDPOINT_XFERTYPE_MASK      0x03    /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL       0
#define USB_ENDPOINT_XFER_ISOC          1
#define USB_ENDPOINT_XFER_BULK          2
#define USB_ENDPOINT_XFER_INT           3

Note the use of yet another gcc feature, the attribute "packed", to force these fields to be laid out exactly as specified, with no alignment gaps.


USB Interfaces


Linux USB Interface Structures

struct usb_interface {
    // array of alternate settings for this interface, in no particular order
    struct usb_host_interface *altsetting;
    struct usb_host_interface *cur_altsetting;  // currently active alternate setting
    unsigned num_altsetting;        // number of alternate settings
    int minor;  // set by usb_register_dev to the minor number, if major number is USB 
    enum usb_interface_condition condition;     // state of binding
    struct device dev;              // interface specific device info
    struct class_device *class_dev;
};
...
struct usb_host_interface {
    struct usb_interface_descriptor desc;
    // array of desc.bNumEndpoint endpoints associated with this
    // interface setting.  these will be in no particular order.
    struct usb_host_endpoint *endpoint;
    unsigned char *extra;   // Extra descriptors
    int extralen;
};

USB Configurations


Linux USB Configuration Structures

struct usb_host_config {
    struct usb_config_descriptor    desc;
    // the interfaces associated with this configuration, stored in no particular order
    struct usb_interface *interface[USB_MAXINTERFACES];
    // Interface information available even when this is not the active configuration
    struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
    unsigned char *extra;   // Extra descriptors 
    int extralen;
};
...
struct usb_config_descriptor {
    __u8  bLength;
    __u8  bDescriptorType;
    __le16 wTotalLength;
    __u8  bNumInterfaces;
    __u8  bConfigurationValue;
    __u8  iConfiguration;
    __u8  bmAttributes;
    __u8  bMaxPower;
} __attribute__ ((packed));
...
struct usb_device {
    int             devnum;          // Address on USB bus
    char            devpath [16];    // Use in messages: /port/port/...
    enum usb_device_state   state;   // configured, not attached, etc
    enum usb_device_speed   speed;   // high/full/low (or error)
    struct usb_tt   *tt;             // low/full speed dev, highspeed hub
    int             ttport;          // device port on that tt hub
    struct semaphore serialize;
    unsigned int toggle[2];          // none bit for each endpoint ([0] = IN, [1] = OUT)
    struct usb_device *parent;       // our hub, unless we're the root
    struct usb_bus *bus;             // Bus we're part of
    struct usb_host_endpoint ep0;
    struct device dev;               // Generic device interface
    struct usb_device_descriptor descriptor; // Descriptor
    struct usb_host_config *config;  // All of the configs
    struct usb_host_config *actconfig; // the active configuration
    struct usb_host_endpoint *ep_in[16];
    struct usb_host_endpoint *ep_out[16];
    char **rawdescriptors;           // Raw descriptors for each config
    int have_langid;                 // whether string_langid is valid yet
    int string_langid;               // language ID for strings
    struct list_head filelist;
    struct dentry *usbfs_dentry;     // usbfs dentry entry for the device
    // Child devices - these can be either new devices
    // (if this is a hub device), or different instances of this same device.
    // Each instance needs its own set of data structures.
    int maxchild;                   // Number of ports if hub
    struct usb_device *children[USB_MAXCHILDREN];

sysfs Representation of USB Devices

Naming scheme: root_hub(-hub_port)*:config.interface

dmesg output:
input: USB HID v1.10 Mouse [Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)] on usb-0000:00:0f.2-2

/sys/devices/pci0000:00/0000:00:0f.2/usb1/1-2/1-2:1.0:
  bAlternateSetting
  bInterfaceClass
  bInterfaceNumber
  bInterfaceProtocol
  bInterfaceSubClass
  bNumEndpoints
  detach_state
  driver
  power
/sys/class/input/event2:
  device -> ../../../devices/pci0000:00/0000:00:0f.2/usb1/1-2/1-2:1.0
/sys/class/input/mouse1:
  device -> ../../../devices/pci0000:00/0000:00:0f.2/usb1/1-2/1-2:1.0
/sys/bus/usb/devices:
  1-2:1.0 -> ../../../devices/pci0000:00/0000:00:0f.2/usb1/1-2/1-2:1.0
/sys/bus/usb/drivers/usbhid:
  1-2:1.0 -> ../../../../devices/pci0000:00/0000:00:0f.2/usb1/1-2/1-2:1.0

Take note of the multiple links to this mouse, classified as an event-generator and a mouse.

The driver seems to be classified as both a USB driver and a human interface device driver.

I originally hoped to use this as an in-class example of how sysfs works, but gave up after spending 2 hrs. trying to make sense out of the USB-related /sys entries for a system with just one USB device (a mouse). It is far too complicated to try to walk through in class. In fact, one wonders whether all that complexity is justified by real value.


/proc/bus/usb/devices

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 4
B:  Alloc= 11/900 us ( 1%), #Int=  1, #Iso=  0
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=0000 ProdID=0000 Rev= 2.06
S:  Manufacturer=Linux 2.6.11.9 ohci_hcd
S:  Product=ServerWorks OSB4/CSB5 OHCI USB Controller
S:  SerialNumber=0000:00:0f.2
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  0mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   2 Ivl=255ms

T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=1.5 MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=045e ProdID=0040 Rev= 3.00
S:  Manufacturer=Microsoft
S:  Product=Microsoft 3-Button Mouse with IntelliEye(TM)
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=usbhid
E:  Ad=81(I) Atr=03(Int.) MxPS=   4 Ivl=10ms

USB Urbs


Urb Utility Functions


An Example of a USB Driver

For a very simple example, take a look at the usbled driver.

For an example of a more useful and more complicated device, take a look at the Konica webcam driver.

© 2005, 2006 T. P. Baker. ($Id: ch13.html,v 1.3 2007/06/05 16:14:32 baker Exp baker $)