| Linux Kernel & Device Driver Programming |
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.
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;
};
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];
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.
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
urb->dev = dev;
urb->context = uvd;
urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
urb->interval = 1;
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = uvd->sbuf[i].data;
urb->complete = konicawc_isoc_irq;
urb->number_of_packets = FRAMES_PER_DESC;
urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length = pktsz;
}
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 $) |