USB总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配。
USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动,设备上的USB Gadget驱动,通常,对于USB这种标准化的设备,内核已经将主机控制器的驱动编写好了,设备上的Gadget驱动通常只运行固件程序而不是基于Linux, 所以驱动工程师的主要工作就是编写主机端的USB设备驱动。
下图表示了Linux中USB子系统的框架结构,和i2c一样,USB子系统也可分为三层:**设备驱动层--USB核心--控制器驱动层*
作为热插拔总线, USB和非热插拔总线最大的区别就是总线无法事前获知设备的信息以及设备何时被插入或拔出,所以也就不能使用任意一种形式将设备信息事前写入内核。
为了解决由于热插拔引起的设备识别问题,USB总线通过枚举的方式来获取一个接入总线的USB设备的设备信息——一个由device->config->interface->endpoint逐级描述的设备,基于分离的思想,USB子系统中设计了一组结构来描述这几个维度的设备信息,相比之下,i2c总线只要一个i2c_client即可描述一个设备.
USB总线上的所有通信都是由主机发起的,所以本质上,USB都是采用轮询的方式进行的。USB总线会使用轮询的方式不断检测总线上是否有设备接入,如果有设备接入相应的D+D-就会有电平变化。然后总线就会按照USB规定的协议与设备进行通信,设备将存储在自身的设备信息依次交给主机,主机将这些信息按照4层模型组织起来。上报到内核,内核中的USB子系统再去匹配相应的驱动,USB设备驱动是面向interface这一层次的信息的
作为一种高度标准化的设备, 虽然USB本身十分复杂, 但是内核已经为我们完成了相当多的工作, 下述的常用设备驱动在内核中已经实现了。很多时候, 驱动的难度不是看设备的复杂程度, 而是看标准化程度
音频设备类
通信设备类
HID设备类
显示设备类
海量存储设备类
电源设备类
打印设备类
集线器设备类
核心结构和方法简述 核心结构基于分离的思想,USB子系统也提供了描述一个USB设备的结构,只不过基于USB协议,完整描述一个USB设备信息需要9个结构,这些结构中,前4个用来描述一个USB设备的硬件信息,即设备本身的信息,这些信息是写入到设备的eeprom的,在任何USB主机中看到的都一样,这些信息可以使用lsusb -v命令来查看; 后5个描述一个USB设备的软件信息,即除了硬件信息之外,Linux为了管理一个USB设备还要封装一些信息,是OS-specific的信息; USB设备硬件信息和软件信息的关系类似于中断子系统中的硬件中断和内核中断,只不过更复杂一点。
usb_device_descriptor来描述一个USB设备的device信息
usb_config_descriptor来描述一个device的config信息
usb_interface_descriptor来描述一个config的interface信息
usb_endpoint_descriptor来描述一个interface的endpoint信息
usb_device描述一个USB的device的软件信息,包括usb_device_descriptor
urb_host_config描述一个USB设备config的软件信息,包括usb_config_descriptor
usb_interface描述一个接口信息
usb_host_interface描述一个interface的设置信息,包括usb_interface_descriptor,我们编写驱动就是针对这一层次的
usb_host_endpoint描述一个interdace的endpoint信息,包括usb_endpoint_descriptor,这是USB通信的最小单位,我们读写一个设备就是针对一个endpoint
usb_driver描述一个usb设备驱动, 也就是USB设备驱动开发的核心结构
usb_driver_id用来标识一个usb设备, 其实例id_table就是usb_driver中的一个域, 由于usb总线中描述一个设备的复杂性, 构造这样一个对象的方法也多种多样
urb (usb request block)是在USB通信过程中的数据载体, 相当于i2c子系统中的i2c_msg, 网络设备驱动中的sk_buff
usb_hcd描述一个SoC中的USB控制器驱动
核心方法usb_fill_int_urb是注册urb的API, 是整个USB通信的核心数据封装
核心结构和方法详述首先说的是那9个描述设备信息的结构, 其中的硬件信息是相互独立的, 分别使用 这些结构在内核"include/uapi/linux/usbch9.h"有定义, 我就不贴代码了
usb_device_descriptor //include/uapi/linux/usbch9.h 258 struct usb_device_descriptor { 259 __u8 bLength; 260 __u8 bDescriptorType; 262 __le16 bcdUSB; 263 __u8 bDeviceClass; 264 __u8 bDeviceSubClass; 265 __u8 bDeviceProtocol; 266 __u8 bMaxPacketSize0; 267 __le16 idVendor; 268 __le16 idProduct; 269 __le16 bcdDevice; 270 __u8 iManufacturer; 271 __u8 iProduct; 272 __u8 iSerialNumber; 273 __u8 bNumConfigurations; 274 } __attribute__ ((packed));