目录
USB驱动框架_WuYuJun's blog的博客-CSDN博客_usb框架
USB原理及驱动框架介绍、编写_Leon_George的博客-CSDN博客_usb驱动框架
USB协议架构及驱动架构_liangdapo的博客-CSDN博客
图文详细解读USB体系架构设计 - 知乎 (zhihu.com)
USB框架
主机控制器,又称host controller,用于控制所有USB设备的通信。Host controller bus上的传输,使用1ms/125us的frame,在frame开始是产生一个SOF包(start of frame)。Out、in事物等传输都是由host轮询发起。每个包的传输都有一个状态阶段同步,接收方可以返回ACK应答接收,NAK重试,STALL错误条件或空设备不可用或断开。
主机hub通过检测数据线状态的变化通知USB主机是否有USB外围设备接入,执行相应的中断处理完成USB device识别匹配(包含USB设备传输类型、ID号、Product、USB速度等信息,暂不谈URB请求生成递交释放)。
设备,device,在usb bus中作从设备。
以linux为例,分为host系统上的驱动程序和device上的驱动程序。前者控制插入其中的usb device,后者控制本身如何作为device与主机通信,我们可以称后者为'USB器件驱动程序 usb gadget drivers'。
USB通信结构
USB数据包分3类:令牌包、数据包和握手包
一个包分7个域:同步序列域、包标志域、地址域、端点域、帧号域、数据域和CRC校验域
同步序列(SYNC),统一0x0000 0001,通过硬件实现。
封包标识符(PID),8位大端,高4bit定义标识,每种数据包有不同标识符。
地址(ADDR),7位可寻址127个设备;默认1个0地址,HOST未对它设定地址前默认,所有每次只能对一个设备枚举。
端点(ENDP),4位组成,最多寻址32个端点。仅用在OUT/IN/SET包
帧号域(frame number),数据域(data)
循环校验码(CRC),校验
在device端,USB设备将非USB格式的数据打包转换成USB格式的数据包,传递至链路层,经过硬件处理、传递到物理层,由物理层通过phy以数据流的形式传输到主机。
host在设备和主机之间发起的传输过程,为事物。事物以2-3个数据包形式进行USB总线传输。
- 令牌阶段,host controller > device 发出命令,device依据PID判断IN/OUT传输。
- 数据传输阶段,controller和device之间传递读写请求,依据令牌阶段的IN/OUT,决定数据传输为DATA0或DATA1来进行数据传输。
- 握手阶段,host向device发送事物类型请求,通过分组标识符来进行识别,接收信息方发送ack表示接收成功;nak表示失败;stall表示不可预知错误。
USB枚举
以USB2.0为例,四线制,Vbus、Gnd、D+/D-半双工。
设备枚举
Host检测device存在并执行一系列操作将设备endpoint添加到主机服务端点列表的过程。
- 设备检测,低速设备将5V置于D-;高速设备将5v置于D+。连接信号由hub检测并报告给主机,一旦检测到设备,主机向设备发送Reset命令。
- 默认状态,收到Reset控制信号序列时,设备进行枚举,如果连接的设备为高速设备,返回“chirp”,完成高速检测过程。一旦速度确定,host读取device descriptor并分配地址。
- 地址状态,设置地址后,主机读取设备所有剩余descriptor table。host确定它可以为设备的接口端点提供服务并提供足够的电力,则发出一个命令,通知设备要激活哪些配置。
- 配置状态,device收到host的配置通知后,就可以使用活动配置运行。
注1:
高速模式 high-speed:480 Mb/s,常缩写为HS模式
全速模式 full-speed:12 Mb/s,常缩写为FS模式
低速模式 low-speed:1.5 Mb/s,常缩写为LS模式
注2:
没有设备连接到主机时,D+/D-数据线的下拉电阻起作用,使两者都在低电平;host来看为SE0状态,SE0持续一段时间后被host认为断开。
设备枚举过程
为插入、供电、初始化、分配地址,配置,获取设备描述符、获取配置描述符、获取字符串描述符和配置设备。
枚举的作用是让主机知道这是什么设备从而安装相应驱动。
具体的枚举过程详细:
USB 枚举/断开过程 - USB中文网 (usbzh.com)
- 插入后,主机检测D+/D- 的电压,确认有设备链接,USB hub通过中断IN 通道向host报告usb连接。
- host收到通知后,通过GetPortStatus获取更多信息,等待100ms设备稳定后发送SetPortStatus复位device,复位后device address = 0,这样host可以使用 0地址与device通信,复位后的设备可以从USB总线上获取小于100mA的电流,用于响应默认地址对pipe0的控制事务。
- Host 向 addr0 的device 的EP0 发送getdescriptor。
- device收到请求后,将其预设的descriptor返回给host
- host收到后,返回一个长度0的数据确认包。
- Host对device再次复位,复位后host对哦地址设备发哦那个SetAddress设置新地址。
- device返回0长度的状态数据包,host返回ack后启用新地址。
- host再次使新地址GetDescriptor,设备返回描述符。
- host第一次配置描述符前18个字节,device返回配置描述符的前18个字节,其数据包中含配置描述符的总长度。
- host更具configuration描述符总长度来下发get命令,device返回全总descriptor。
- 如果还有stringdescriptor,系统还会get(还有HID硬编码描述符,报告描述符,physical描述符啥的)
- 然后host为device选择一个config
USB描述符框架
下图展示USB设备、配置、接口和端点的包含关系
端点 endpoint
USB通信最基本的形式,单向pipe,主从为端点out,从主为端点in。
每个USB设备都有一个EP0的控制端点。
端点数据传输方式,控制、中断、批量、等时
1、控制传输
双向传输(唯一可以进行IN/OUT),在设备首次连接时配置设备,先是插入检测,检测完毕后设备采用EP0以默认地址和主机进行控制传输来数据交互,传输通道叫控制管道。
2、中断传输
用于实时可靠的传输场景,并以不低于设备指定速率进行传输。中断数据通常由一个或多个字节的事件通知、字符或坐标组成。支持中断传输的设备有USB鼠标键盘等,中断端点在端点descriptor中要报告host对此端点的查询时间,host保证在小于这个interval的间隔范围内安排一次传输。
3、批量传输
单向传输,支持批量传输设备有U盘等,进行大量数据传输,具有突发性,通过在硬件中使用错误检测并采用前面所说的错误重传机制保证数据的准确性,不具备实时性。应用场景如USB打印机、扫描仪、大容量存储设备。
4、同步传输
占用预先约定好的USB带宽以及传输延迟,称流式实时传输。需要特定带宽以及延迟要求,与特定设备的相关数据吞吐率以及端点的缓冲管理有关。USB色相头同样进行大量数据传输,数据准确性不保证,对实时性要求高。没有握手阶段。
接口 interface
部分USB设备具有多个接口,每个接口处理一种逻辑。一个驱动对应一个接口对应一个基本功能。以声卡为例,录音和播放为两个接口对应两个驱动。
配置 config
USB设备可以有多个配置,可以在配置之间切换来改变设备状态。同一时刻只有一个配置处于活动。
设备 device
设备包含不同级别的配置,有一个或多个。
xHCI,USB3.0设备(5Gbps);
EHCI,高速USB2.0 (480Mbps);
UHCI,低速USB1.0 (1.5Mbps)和全速USB1.1 (12Mbps);Intel主导软件简单,硬件复杂。
OHCI,低速USB1.0 (1.5Mbps)和全速USB1.1 (12Mbps);Microsoft主导,硬件简单,软件复杂。
字符串 String
除以上4种之外,还有一种可选的描述符,字符串描述符,为方便使用USB设备的应用人员。
使用自然语言来描述设备的功能,生产厂家,生产序列号等。
硬编码 HID
硬编码描述符,报告描述符,physical描述符等,HID设备才有。
pyusb获取的usb设备
DEVICE ID 8888:0007 on Bus 001 Address 048 =================
bLength : 0x12 (18 bytes)//本描述符的size
bDescriptorType : 0x1 Device//描述符的类型,这里是设备描述符DEVICE
bcdUSB : 0x110 USB 1.1//指明usb的版本,比如usb2.0
bDeviceClass : 0x2 Communications Device//类
bDeviceSubClass : 0x0//子类
bDeviceProtocol : 0x0//指定协议
bMaxPacketSize0 : 0x40 (64 bytes)//端点0对应的最大包大小
idVendor : 0x8888//厂家ID
idProduct : 0x0007//产品ID
bcdDevice : 0x100 Device 1.0//设备的发布号
iManufacturer : 0x1 Error Accessing String//字符串描述符中厂家ID的索引
iProduct : 0x2 Error Accessing String//字符串描述符中产品ID的索引
iSerialNumber : 0x3 Error Accessing String//字符串描述符中设备序列号的索引
bNumConfigurations : 0x1//配置描述符的个数,表示有多少个配置描述符
CONFIGURATION 1: 100 mA ==================================
bLength : 0x9 (9 bytes)//描述符的长度
bDescriptorType : 0x2 Configuration//描述符类型的编号
wTotalLength : 0x43 (67 bytes)//配置所返回的所有数据的大小
bNumInterfaces : 0x2//配置所支持的接口个数, 表示有多少个接口描述符
bConfigurationValue : 0x1//Set_Configuration命令需要的参数值
iConfiguration : 0x0 //描述该配置的字符串的索引值
bmAttributes : 0xa0 Bus Powered, Remote Wakeup//供电模式的选择
bMaxPower : 0x32 (100 mA)//设备从总线提取的最大电流
INTERFACE 0: CDC Communication =========================
bLength : 0x9 (9 bytes)//描述符的长度
bDescriptorType : 0x4 Interface//描述符类型的编号
bInterfaceNumber : 0x0//接口的编号
bAlternateSetting : 0x0//备用的接口描述符编号,提供不同质量的服务参数.
bNumEndpoints : 0x1//要使用的端点个数(不包括端点0), 表示有多少个端点描述符,比如鼠标就只有一个端点
bInterfaceClass : 0x2 CDC Communication//接口类型,与驱动的id_table对应
bInterfaceSubClass : 0x2//接口子类型
bInterfaceProtocol : 0x1//接口所遵循的协议
iInterface : 0x0 //描述该接口的字符串索引值
ENDPOINT 0x83: Interrupt IN ==========================
bLength : 0x7 (7 bytes)//描述符的长度
bDescriptorType : 0x5 Endpoint//描述符类型的编号
bEndpointAddress : 0x83 IN//端点编号,比如端点1,就是1
bmAttributes : 0x3 Interrupt//端点的属性, 比如中断传输类型,输入类型
wMaxPacketSize : 0x40 (64 bytes)//一个端点的最大包大小,
bInterval : 0x1//间隔时间,用在中断传输上,比如间隔时间查询鼠标的数据
INTERFACE 1: CDC Data ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x1
bAlternateSetting : 0x0
bNumEndpoints : 0x2
bInterfaceClass : 0xa CDC Data
bInterfaceSubClass : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x0
ENDPOINT 0x81: Bulk IN ===============================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x2 Bulk
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x0
ENDPOINT 0x2: Bulk OUT ===============================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x2 OUT
bmAttributes : 0x2 Bulk
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x0