一、USB子系统基本框架
USB是Universal Serial Bus的缩写,中文译为通用串行总线,USB出现之前,计算机领域中的接口太多太繁杂,USB出现之后减少了接口的种类,总的来说就是设计出了一个万能的接口,各种外设都能用同一种接口,所以才冠以“通用(是Universal)”为名。
USB设备,从物理上的逻辑结构来说,包含了主机Host端和设备Device端。2个硬件概念:
- USB Host:它跟处理器相连,处理器通过USB Host跟各类USB设备通信。USB Host中集成有一个root hub
- USB Device:这分为两类设备
- Hub:用来扩展USB接口
- Function:就是普通的USB设备,比如U盘、声卡等
linux内核支持两种主要类型的USB驱动程序:USB设备驱动程序(主机侧)和USB gadget drivers(设备侧)。主机侧的USB设备驱动程序提供了访问USB设备的方法,封装成操作函数供应用程序对USB设备进行操作(通信)。USB gadget driver则用于模拟出一个USB设备。假设有一个搭载linux系统的计算机系统,同时具备USB设备所需的硬件,USB gadget driver使这个系统被识别为一个USB设备,并具有相应功能。
USB子系统采取主从的通信结构,一切的通信都是由Host端主动发起。
二、基础知识
- USB、设备插入Pc机,是插入到USB控制器内部的USBhub。Pc机自动寻找和安装驱动。这个工作是由USB总线驱动完成的,USB总线驱动程序负责识别插入的USB设备,并安装对应的驱动程序。
- hub结构:树状。cpu与host通信,host连接root hub。roothub上可直连usbdev也可以连接usbhub。usbhub最多连接6层。
- 多个设备连接到pc机,pc机如何识别?
每个usb设备临时的编号。这个编号是在usb设备接入到usb总线时,usb总线驱动程序分配的。在usb总线驱动为其分配驱动之前,新设备使用特殊编号“0”。 - usb接口有四根信号线:power、GND、以及两根差分信号线D+和D-。
- usb设备插入,usb总线驱动如何得知?
pc端,usb接口D+或D-内部连接了下拉电阻;usb设备内部,D+和D-连接上拉电阻。设备插入usb接口,这两个接口中,会有电平变化。 - usb设备:lowspeed、fullspeed和highspeed。规定没有设备同时支持低速模式和高速模式。如何识别设备类型?
低速设备:D-接下拉电阻;
全速设备和高速设备:D+接下拉电阻。
通过这个区别,可以区分低速设备和其他两类设备。
全速设备和高速设备如何区分呢?
设备连接后,usbhub会对设备发送复位信号,若usbhub识别其为全速设备或者高速设备,设备会向usb设备发送信号,表示自己支持高速模式。 - 连接后如何识别到断开?
对于低速设备和全速设备:断开设备后,差分信号引脚会呈现00;
对于高速设备:高速设备连接到pc,pc知晓其为高速设备并且自己也支持高速模式,复位后将会断开上拉电阻并且在pc端和usb设备的差分数据引脚上都接上45欧姆的下拉电阻(防止反射信号,若不接45欧姆的下拉电阻,发送的信号和反射的信号叠加,会使得信号幅度很大,接了下拉电阻反射信号迅速衰减),usb设备断开后,反射信号会叠加,使得信号幅度很大,pc由此识别。 - 数据信号:
usb通过nrzc信号传输信息。传输前 - 同步方式:提前设定波特率;clk信号线;发送前发送同步信号
- 位填充:连续发送多个1,信号电平不变,可能产生误差。故连续发送六个1后,强制填充一个0。
二、USB协议数据格式
1、传输 Control, Bulk, Interrupt, Isochronous
2、 一个控制传输包含多个事务(一个建立事务、多个数据事务、一个数据事务作为结束)
其他三种传输仅包含一个事务,对于其他传输,“传输”和“事务”是对等的。
3、一个事务由多个包组成,基本组成:令牌阶段、数据阶段、握手阶段
4、包的结构: sop sync pid data crc eop
三、USB协议层数据格式和设备枚举过程
-
协议层数据格式
USB传输的基本单位是包(Packet),包的类型由PID表示。一个单纯的包,是无法传输完整的数据。
为什么?比如想输出数据,可以发出OUT令牌包,OUT令牌包可以指定目的地。但是数据如何传输呢?还需要发出DATA0或DATA1数据包。设备收到数据后,还要回复一个ACK握手包。
所以,完整的数据传输,需要涉及多个包:令牌包、数据包、握手包。这个完整的数据传输过程,被称为事务(Transaction)。
有些事务需要握手包,有些事务不需要握手包,有些事务可以传输很大的数据,有些事务只能传输小量数据。
有四类事务:
- 批量事务:用来传输大量的数据,数据的正确性有保证,时效没有保证。
- 中断事务:用来传输周期性的、小量的数据,数据的正确性和时效都有保证。
- 实时事务:用来传输实时数据,数据的正确性没有保证,时效有保证。
- 建立事务:跟批量事务类似,只不过令牌包是SETUP令牌包。
有四类传输(Transfer):
- 批量传输:就是使用批量事务实现数据传输,比如U盘。
- 中断传输:就是使用中断事务实现数据传输,比如鼠标。
- 实时传输:就是使用实时事务实现数据传输,比如摄像头。
- 控制传输:由建立事务、批量事务组成,所有的USB设备都必须支持控制传输,用于"识别/枚举"
暂时记住这个关系:
- BIT组成域(Field)
- 域组成包(Packet)
- 包组成事务(Transaction)
- 事务组成传输(Transfer)
-
控制传输
一个控制传输由三个阶段组成:建立阶段、数据阶段、状态阶段。
建立阶段表明此次控制传输的意图,即想做的事情是什么。“想做的事情”在建立事务的数据包中用固定格式的数据传达:
-
设备的枚举过程
一切的usb传输都是host主动发起。usb设备接入后,一切usb传输都是由host端主动发起的,当host端发现新设备接入后,怎样读取里面的信息呢?
- 读取设备描述符
- 设置地址
- 读取设备描述符
- 读取配置描述符
- 设置配置
上述的这些操作,是通过控制传输实现的。一个控制传输,由建立阶段、数据阶段、状态阶段组成。不是每个传输都有数据阶段,比如设置地址就没有,新地址信息存储在建立阶段data中。
四、USB描述符
Host使用控制传输来识别设备、获取配置、设置设备地址、设置配置。Host通过读取或设置配置描述符来完成这些工作。
一个USB设备,
-
一个配置下,可以有多个接口(Interface),接口等同于功能(Function)。比如USB耳机有两个接口(功能):声音收发、按键控制。
-
一个接口,可能有多个设置(Setting),比如默认设置下它使用较低的带宽,可以选择其他设置以使用更高带宽。
-
一个接口,由一个或多个端点(Endpoint)组成。端点0属于整个设备的,端点0是双向的。接口还可以有其他端点,这些端点是单向的,要么是批量(Bulk)端点、要么是中断(Interrupt)端点、要么是同步(Isochronous)端点。
描述它们的配置和功能的就是USB描述符。
一个USB设备,
- 只有一个设备描述符:用来表示设备的ID、它有多少个配置、它的端点0一次最大能传输多少字节数据
- 可能有多个配置描述符:用来表示它有多少个接口、供电方式、最大电流
- 一个配置描述符下面,可能有多个接口描述符:用来表示它是哪类接口、有几个设置(Setting)、有几个端点
- 一个接口描述符符下面,可能有多个端点描述符:用来表示端点号、方向(IN/OUT)、类型(批量/中断/同步)
五、libusb的使用
在主机侧,应用访问设备的流程如下:
libusb在USB控制器驱动这一层之上,使用USB控制器驱动提供的操作函数,向app提供了通用的API接口。app跳过USB设备驱动,通过USB控制器驱动访问设备。而本在USB设备驱动中需要处理的数据解析等工作就可以在用户态来处理,因此也可以理解成用户态的USB设备驱动。
libusb支持所有的传输类型(控制/批量/中断/实时),有两类API接口:同步(Synchronous,简单),异步(Asynchronous,复杂但是更强大)。它是轻量级的、线程安全的。还支持热拔插。
用法: