术语表
术语 | 英文全称 | 含义 |
---|---|---|
USB | Universal Serial Bus | 通用串行总线 |
CDC | Communications Device Class | 通信设备类,用于实现串行通信功能,如虚拟串口 |
HID | Human Interface Device Class | 人机接口设备类,用于输入设备,如键盘、鼠标等 |
MSC | Mass Storage Class | 大容量存储设备类,用于存储设备,如外部硬盘、SD 卡读卡器等 |
VID | Vendor ID | 供应商 ID,标识 USB 设备制造商 |
PID | Product ID | 产品 ID,标识 USB 设备的具体型号 |
UDC | USB Device Controller | USB 设备控制器(Device端) |
HDC | Host Device Controller | USB主机设备控制器(Host端) |
USB描述符
USB 描述符是 USB 设备用于自我描述的标准结构。它们为设备提供了设备的各种信息,以便主机可以正确识别、配置和使用设备。一个典型的USB设备描述符链结构可能如下图
1 | Device Descriptor |
设备描述符(Device Descriptor)
设备描述符包含有关 USB 设备的基本信息,如供应商 ID(VID)、产品 ID(PID)、设备类别等。它是USB主机枚举USB设备申请的第1个描述符,每个设备有且仅有一个设备描述符
1 | struct usb_device_descriptor { |
配置描述符(Configuration Descriptor)
配置描述符包含关于设备电源需求和配置的详细信息。一个USB设备至少有一个或者多个配置,但通常只有一个处于活动状态,每一种配置都对应一个配置描述符的集合,配置描述符集合主要由标准配置描述符、接口描述符、端点描述符、(类描述符HID、UVC、CDC等类功能描述符),报告描述符和物理描述符单独返回给主机
1 | struct usb_config_descriptor { |
接口描述符(Interface Descriptor)
接口描述符描述了一个配置中的单个接口。每个接口可以有多个端点。接口描述符 不能单独返回给主机,必须跟在配置描述符后面返回
1 | struct usb_interface_descriptor { |
端点描述符(Endpoint Descriptor)
端点描述符包含主机要确定每个端点的带宽要求所需要的信息。每个接口可以有多个端点描述符。
1 | struct usb_endpoint_descriptor { |
USB传输的对象:端点(endpoint)
- 我们说”读U盘”、“写U盘”,可以细化为:把数据写到U盘的端点1,从U盘的端点2里读出数据
- 除了端点0外,每一个端点只支持一个方向的数据传输;
- 端点0用于控制传输,既能输出也能输入;
- 每一个端点都有传输类型,传输方向;
- 端点是USB设备通信的基本单位,所有通信都是从端点发起的
字符串描述符(String Descriptor)
字符串描述符包含设备、制造商和产品等的人类可读信息。这些信息可以通过索引在其他描述符中引用
1 | struct usb_string_descriptor { |
枚举
USB 枚举(Enumeration)是指主机在检测到一个新的 USB 设备连接后,识别、配置并准备与该设备进行通信的过程。一旦确认设备类型,主机就可以根据这些信息来加载合适的驱动程序。
USB协议定义了设备的6中状态,仅在而枚举过程中就经历了4个状态的迁移:上电状态、默认状态、地址状态、配置状态(另外两种是连接状态和挂起状态)
上电过程
用户把USB设备插入USB端口(hub),此时USB设备处于加电状态,它所连接的端口是无效的
设备类型检测
Hub端会根据数据线(D+ 和 D-)上的电压变化,两个数据线上上哪一个被拉高,从而识别出设备是低速、还是非低速设备(高速/全速)。
Host了解连接的设备
Hub利用自己的中断端点向Host报告它的端口状态(对于这个过程,设备是看不到的,也不关心),如果有连接断开事件,Host向Hub发送一个Get_Port_Status请求了解更多。
此时Hub将检测到的速度类型信息返回给Host
Hub复位设备
连接成功之后至少等待100ms确保电源稳定,主机控制器向Hub发出Set_Port_Freature请求让hub复位刚才连接成功的端口,持续最少10ms
确认是高速设备还是全速设备
不论是Hub还是设备,起始状态都将以全速模式运行,进一步的进行高速检测,如果确认对方支持高速,再切换到高速模式
发送复位信号后,设备会发送 chirp 信号。主机识别 chirp 信号,确定设备为高速设备。
Hub建立设备和主机之间的信道
主机不停发送Get_Port_Status请求,确认设备是否复位成功。复位成功,对应的USB设备地址变成0,主机就可以通过控制传输,与默认地址0,端口号0的设备进行通信
获取设备描述符
主机通过发送 GET_DESCRIPTOR 请求读取设备的部分设备描述符,主机读取设备描述符的第 8 个字节,以获取设备的最大包大小(bMaxPacketSize0)
此时系统为了设备进入一个确定的状态,会要求hub对设备再一次进行复位操作(但协议中没有该规定)
设备地址分配
主机控制器发送 SET_ADDRESS 请求,分配一个唯一的地址(1-127)。设备在确认收到该请求后,进入地址状态,使用分配的地址进行后续通信。一旦设备掉电消失、重新进行枚举,地址也将重新分配。
再次获取设备描述符
主机再次发送 GET_DESCRIPTOR获取设备所有的详细信息(其它字段的解析)
获取配置描述符及其它描述符
驱动匹配及挂载
这个阶段主机已经拿到了设备的全部信息,将匹配对应的驱动。主机首先announce_device说明设备已经找到;调用设备驱动模型提供的接口device_add,将设备添加到usb总线的设备列表里;usb总线将遍历驱动列表里的驱动,调用usb_device_match将进行匹配;匹配成功调用device_bind_driver函数,现在设备控制权交到设备驱动上
对于复合设备,通常是不同的接口配置给不同的驱动,因此需要等待设备被配置并把接口使能之后才能挂载驱动
设置设备配置
主机选择一个配置,发送 SET_CONFIGURATION 请求配置设备,设备进入配置状态,准备与主机进行正常的数据通信。
复合设备
复合设备与组合设备
USB Composite Device(复合设备)
一个USB设备芯片实现了多个USB设备功能,其是通过USB接口描述符来实现不同的设备功能。软件工程师复合的USB设备
- 只有一个Function,只有一套PID VID
USBCompound Device(组合设备)
从外观或者包装上来看的这个USB设备,如果其USB接口是其一个USB集线器的上游端口,这类设备被定义为USB组合设备。硬件工程师组合的USB设备
- 每个设备有独立的设备描述符,分配独立的USB总线地址
- 内嵌多个Function,每个设备的PID VID一般不相同
- 每个设备有独立的配置描述符,并且都需要独立在USB总线上传输
结构体及函数
类型 | 名称 | 功能 |
---|---|---|
struct | usb_function | 描述配置的一个功能 |
struct | usb_configuration | 代表一个gadget配置 |
struct | usb_composite_driver | 将配置分组到一个gadget中(每个驱动有且只有一个) |
struct | usb_composite_dev | 代表一个复合 USB gadget(驱动不需要关心) |
struct | usb_function | 代表一种usb的功能(CDC、MSG…) 需要使用不同功能的alloc函数获取实例 |
function | int usb_add_function( struct usb_configuration* config, struct usb_function * function); |
将函数添加到配置中,每个function调用其的 bind进行资源分配 复合驱动多个function需要调用多次 |
function | int usb_add_config ( struct usb_composite_dev * cdev, struct usb_configuration * config, int (*bind) (struct usb_configuration *`)); |
将配置添加到设备上(每个驱动有且只有一个) (第三个参数回调的实现就需要调用usb_add_function) |
function | int usb_composite_probe ( struct usb_composite_driver * driver); |
注册复合驱动程序 |
FAQ
usb主机如何区分设备时高速设备、全速设备还是低速设备?
主机端数据线D+和D-都有一个阻值在14.25k到24.8k的下拉电阻,而在设备端,D+(全速、高速)和D-(低速)上有一个1.5k的上拉电阻。
差分电平检测。低速设备:D- 上拉电阻将电平拉高;全速/高速设备:D+ 上拉电阻将电平拉高。
高速信号检测。hub检测到有设备插入/上电时,向主机通报,主机发送Set_Port_Feature请求让hub复位新插入的设备。设备复位操作是hub通过驱动数据线到复位状态SE0(Single-ended 0,即D+和D-全为低电平),并持续至少10ms。
高速设备初始是以一个全速设备的身份出现的。USB2.0的hub把它当作一个全速设备,之后,hub和设备通过一系列握手信号确认双方的身份。在这里对速度的检测是双向的,比如高速的hub需要检测所挂上来的设备是高速、全速还是低速,高速的设备需要检测所连上的hub是USB2.0的还是1.x的,如果是前者,就进行一系列动作切到高速模式工作,如果是后者,就以全速模式工作。