USB Concepts for Linux Kernel Driver Developers
A Practical Guide to Architecture, Transfers, and Enumeration
1. USB Architecture: Tiered Star Topology
USB uses a host-centric, tiered star topology managed by the Linux kernel through:
Linux handles hub connections via drivers/usb/core/hub.c.
2. USB Device Framework: Descriptors in Depth
Hierarchical Structure
USB devices describe themselves through a tree of descriptors:
Key Descriptors in Linux:
Composite vs. Compound Devices:
3. USB Data Transfers: URBs & Endpoints
URB (USB Request Block) Lifecycle
URBs are the backbone of USB communication in Linux:
Transfer Types in Practice:
4. Device Enumeration: Step-by-Step
Detailed Enumeration Flow
When a device is plugged in:
// From drivers/usb/core/message.c
usb_get_device_descriptor(udev, 8); // Initial 8-byte read
usb_get_configuration(udev); // Full configuration
static struct usb_device_id my_table[] = {
{ USB_DEVICE(0xabcd, 0x1234) },
{ USB_INTERFACE_INFO(USB_CLASS_AUDIO, 1, 0) },
{}
};
static int my_probe(struct usb_interface *intf,
const struct usb_device_id *id) {
struct usb_device *udev = interface_to_usbdev(intf);
// ...
}
Sysfs Representation:
/sys/bus/usb/devices/
├── 1-0:1.0 # Root hub
├── 2-1 # Device at port 1
└── 2-1:1.0 # Interface of device 2-1
5. USB Classes: HID Deep Dive
HID Report Descriptor Example
A mouse descriptor defines buttons and movement axes:
// Example HID Report Descriptor
static __u8 mouse_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x05, 0x09, // Usage Page (Buttons)
0x19, 0x01, // Usage Minimum (Button 1)
0x29, 0x03, // Usage Maximum (Button 3)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x03, // Report Count (3 buttons)
0x75, 0x01, // Report Size (1 bit per button)
0x81, 0x02, // Input (Data,Var,Abs)
0x95, 0x01, // Report Count (1 padding bit)
0x75, 0x05, // Report Size (5 bits)
0x81, 0x03, // Input (Const,Var,Abs)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x00, 0x80, // Logical Minimum (-32768)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16 bits)
0x95, 0x02, // Report Count (2 fields: X/Y)
0x81, 0x06, // Input (Data,Var,Rel)
0xC0, // End Collection
0xC0, // End Collection
};
HID Driver Workflow in Linux:
static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) {
struct hid_device *hid;
hid = hid_allocate_device();
usbhid = kzalloc(sizeof(*usbhid), GFP_KERNEL);
// Parse report descriptor
hid_parse_report(hid, report_desc, report_len);
hidinput_connect(hid); // Create /dev/input/eventX node
}
input_report_key(hidinput->input, BTN_LEFT, button_state & 0x01);
input_sync(hidinput->input);
Debugging HID:
6. Power Management States
Conclusion
For Linux driver developers, focus on:
Use tools like usbmon for advanced debugging. For specifications, refer to USB Concepts.