Lazy loaded image
USB专题07 - USB设备驱动模型
Words 4888Read Time≈ 13 min
2026-10-7

USB 设备驱动模型

本页依据课程配套源码《08_USB设备驱动模型.md》整理,聚焦 Linux USB 主机侧的接口级匹配、pipe、同步/异步传输与 URB 取消。
核心结论:usb_driver 通常匹配 configuration 下的 usb_interface;异步 I/O 的资源回收必须和 disconnect/complete 回调同步设计。
参考资料:
  • Linux内核源码:`include\linux\usb.h`
  • Linux内核源码:`drivers\hid\usbhid\usbmouse.c`

1. BUS/DEV/DRV模型

配图:image-20221010144529823(课程原始图片路径:pic/62_usb_bus_dev_drv.png)
  • "USB接口"是逻辑上的USB设备,我们编写的usb_driver驱动程序,支持的是"USB接口":
  • USB控制器或Hub识别出USB设备后,会创建、注册usb_deive
  • usb_device被"drivers\usb\core\generic.c"驱动认领后,会选择、设置某个配置
  • 这个配置下面的接口,都会分配、设置、注册一个usb_interface

2. 接口函数

在USB设备驱动程序中,能使用的USB函数都在这个头文件里:`include\linux\usb.h`。

2.1 pipe

使用这些接口函数的主要目的是传输数据,传输数据的对象是USB设备里的某个endpoint,这被称为pipe:

2.2 同步传输函数

对于控制传输、批量传输、中断传输,有3个同步函数可以用来直接发起传输。这些函数内部会创建、填充、提交一个URB("usb request block"),并等待它完成或超时。
函数原型如下:

2.3 异步传输函数

使用URB进行传输时,它是异步方式:需要先分配、构造、提交一个URB("usb request block"),当传输完成后,它的回调函数被调用。
关键就在于需要填充URB:
  • dev:跟谁传输数据
  • pipe:跟哪个pipe传输数据
  • buffer:里面存有要发送的数据,或者用来接收要读取的数据
  • 数据长度
  • 回调函数
2.3.1 分配和释放URB
函数原型如下:
2.3.2 分配/释放DMA Buffer
发起USB传输时,数据保存在buffer里。这个buffer可以是一般的buffer,也可以是DMA Buffer。
对于一般的buffer,在提交URB时会临时分配一个DMA Buffer:
  • 发送数据时:函数内部会先从一般buffer中把数据复制到DMA Buffer,在提交给USB控制器
  • 读取数据时:USB控制器先把数据传到DMA Buffer,函数内部在把DMA Buffer的数据复制到一般buffer
  • 中间增加了一次数据的拷贝,效率低
我们可以直接使用DMA Buffer,函数原型如下:
2.3.3 填充URB
对于控制传输、批量传输、中断传输,分别有如下函数:
如果URB使用DMA Buffer,那么还需要设置一个flag表明这点:
2.3.4 提交URB
构造好URB后,需要提交到USB系统里,才能启动传输。
2.3.5 取消URB
已经提交的URB,可以取消它,有2个函数:
  • usb_kill_urb:这是一个同步函数,它会等待URB结束
  • usb_unlink_urb:这是一个异步函数,它不会等待URB结束,USB控制器驱动会调用它的回调函数

学习与实现检查

  • 确认驱动按 interface 匹配,而不是把整个 usb_device 误当作功能驱动的匹配对象。
  • 提交 URB 后不释放 URB 或传输缓冲区;必须等完成回调,或在退出路径使用 usb_kill_urb()。
  • 同步传输接口会等待,不能从中断、bottom half 或完成回调中调用。
  • disconnect 中先阻止新 I/O,再取消已提交 URB,最后释放 buffer、URB 和私有数据。
  • 完成回调在重提 URB 前要判断停止状态,避免拔出设备后重新开始 I/O。
上一篇
C++ String 常用操作
下一篇
嵌入式工程师习题集

Comments
Loading...