USB 子系统
USB 架构概览
用户空间
│ libusb / /dev/bus/usb/
▼
┌─────────────────────────────────────┐
│ USB 核心层 │
│ usb_register_driver / urb 管理 │
└──────┬──────────────────────────────┘
│
┌──────▼──────────────────────────────┐
│ USB 主机控制器驱动 │
│ xHCI (USB3) / EHCI (USB2) / OHCI │
└──────┬──────────────────────────────┘
│ USB 总线
USB 设备(HID / CDC / 存储 / 自定义)USB 设备驱动框架
c
#include <linux/module.h>
#include <linux/usb.h>
#define MY_VENDOR_ID 0x1234
#define MY_PRODUCT_ID 0x5678
struct my_usb_priv {
struct usb_device *udev;
struct usb_interface *interface;
u8 bulk_in_ep;
u8 bulk_out_ep;
size_t bulk_in_size;
u8 *bulk_in_buf;
};
static int my_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct my_usb_priv *priv;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *ep;
int i, ret;
priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->udev = usb_get_dev(udev);
priv->interface = interface;
/* 遍历端点,找到 Bulk IN 和 Bulk OUT */
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
ep = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(ep)) {
priv->bulk_in_ep = ep->bEndpointAddress;
priv->bulk_in_size = usb_endpoint_maxp(ep);
}
if (usb_endpoint_is_bulk_out(ep)) {
priv->bulk_out_ep = ep->bEndpointAddress;
}
}
if (!priv->bulk_in_ep || !priv->bulk_out_ep) {
dev_err(&interface->dev, "could not find bulk endpoints\n");
ret = -ENODEV;
goto error;
}
priv->bulk_in_buf = devm_kmalloc(&interface->dev,
priv->bulk_in_size, GFP_KERNEL);
if (!priv->bulk_in_buf) {
ret = -ENOMEM;
goto error;
}
usb_set_intfdata(interface, priv);
dev_info(&interface->dev, "USB device connected: VID=%04x PID=%04x\n",
id->idVendor, id->idProduct);
return 0;
error:
usb_put_dev(udev);
return ret;
}
static void my_usb_disconnect(struct usb_interface *interface)
{
struct my_usb_priv *priv = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
usb_put_dev(priv->udev);
dev_info(&interface->dev, "USB device disconnected\n");
}
/* Bulk 传输 */
static int my_usb_bulk_write(struct my_usb_priv *priv,
void *data, size_t len)
{
int actual_len;
return usb_bulk_msg(priv->udev,
usb_sndbulkpipe(priv->udev, priv->bulk_out_ep),
data, len, &actual_len, 5000); /* 5s 超时 */
}
static const struct usb_device_id my_usb_table[] = {
{ USB_DEVICE(MY_VENDOR_ID, MY_PRODUCT_ID) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0000, 0x0000,
USB_CLASS_CDC_DATA, 0, 0) },
{ }
};
MODULE_DEVICE_TABLE(usb, my_usb_table);
static struct usb_driver my_usb_driver = {
.name = "my-usb-driver",
.probe = my_usb_probe,
.disconnect = my_usb_disconnect,
.id_table = my_usb_table,
};
module_usb_driver(my_usb_driver);
MODULE_LICENSE("GPL");URB(USB Request Block)异步传输
c
struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
/* 填充 Bulk URB */
usb_fill_bulk_urb(urb,
priv->udev,
usb_rcvbulkpipe(priv->udev, priv->bulk_in_ep),
priv->bulk_in_buf,
priv->bulk_in_size,
my_urb_complete, /* 完成回调 */
priv /* 上下文 */
);
/* 提交 URB */
ret = usb_submit_urb(urb, GFP_KERNEL);
/* 完成回调(在中断上下文中执行) */
static void my_urb_complete(struct urb *urb)
{
struct my_usb_priv *priv = urb->context;
if (urb->status) {
dev_err(&priv->interface->dev, "URB error: %d\n", urb->status);
return;
}
/* 处理接收到的数据 urb->actual_length 字节 */
/* 重新提交以持续接收 */
usb_submit_urb(urb, GFP_ATOMIC);
}
/* 取消 URB */
usb_kill_urb(urb);
usb_free_urb(urb);端点类型
| 类型 | 方向 | 特点 | 典型用途 |
|---|---|---|---|
| Control | 双向 | 可靠,低速 | 设备枚举、配置 |
| Bulk | 双向 | 可靠,无带宽保证 | 大数据传输(存储) |
| Interrupt | IN/OUT | 低延迟,周期轮询 | HID(键鼠)、串口 |
| Isochronous | IN/OUT | 实时,允许丢包 | 音视频流 |
调试工具
bash
# 查看 USB 设备树
lsusb -t
# 查看设备详细信息
lsusb -v -d 1234:5678
# 实时监控 USB 事件
udevadm monitor --udev --subsystem-match=usb
# usbmon 抓包(需 CONFIG_USB_MON=y)
modprobe usbmon
cat /sys/kernel/debug/usb/usbmon/1u