usb总线驱动学习总结
一、概述
二、usb总线硬件原理
三、usb总线通信协议
四、uboot基于DM框架的usb驱动代码流程
一、概述
本文旨在对usb总线驱动的学习做一个总结;
先描述usb总线的硬件结构及工作原理;
然后描述usb总线通信协议规范的主要内容,搞清楚usb主机和usb设备是如何基于包进行通信的;
最后,基于usb总线的硬件原理和usb通信协议,描述uboot下面基于DM驱动框架的usb驱动软件是如何实现的,先描述usb控制器驱动初始化,usb hub的扫描配置,然后扫描usb hub的port上连接的usb设备,最后,以dm9601 usb网卡驱动为例,说明如何通过usb总线访问dm9601内部的寄存器,如何通过usb总线与dm9601进行数据收发。
二、usb总线硬件原理
介绍usb总线的硬件结构,整体框架、组成部件(usb控制器、hub、usb设备)、总线拓扑结构。
2.1 usb总线拓扑结构
下图是usb总线的拓扑结构,由usb控制器、hub以及各类usb设备构成一种树型结构,其中usb控制器内部有且仅有一个root hub。
下图是hub的框图,hub是用来连接usb设备的,一般hub有多个port,每个port可连接一个usb设备,也可连接另一个hub继续扩展。
2.2 usb控制器结构框图
下图是一个usb控制器的结构框图,控制器内部包括处理usb协议相关的组件、寄存器、数据包缓存、root hub、以及用于连接外部差分信号线的USB PHY;
2.3 usb设备结构框图(DM9601)
如下是usb设备dm9601网卡的结构框图,除了网卡相关的mac和phy组件外,还包括一个usb控制接口;
三、usb总线通信协议
usb通信协议规定了usb设备和usb总线通信的规范,所有厂商的usb设备都遵守这些规范,因此所有厂商的usb设备都可以基于usb通信协议进行通信;
对于usb设备,usb通信协议规定,每个usb设备都需要有设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符(可选)、这些描述符内容结构固定,描述了设备的属性和具备的功能;usb主机通过这些描述符对设备进行类别识别、配置,并匹配对应的驱动程序,比如在usb设备枚举时,通过产商ID匹配驱动程序;
对于usb主机和usb设备的通信,usb协议规定了usb主机和usb设备之间如何实现通信:
usb主机和设备的通信使用主从模式,数据读写只能由主机发起,比如usb设备不能主动发数据给主机,必须由主机给usb设备发读命令,然后usb设备再将数据发给主机;
usb主机和设备的信息传输基于包实现,包由多个字段构成,usb协议定义了4种类型的包:令牌包、数据包、握手包、特殊包;usb主机和设备的每次通信都要互相收发多个包实现,比如usb主机要从usb设备读一个数据:首先发一个令牌包告知设备要读数据、然后设备将数据通过数据包发给主机、主机收到数据后发送握手包给设备确认收到数据;
需要说明的是,usb设备功能的控制由端点实现,每个usb设备都有多个端点,各端点分别控制不同的功能;对于usb主机来说,可以通过读取端点描述符知晓对应端点的属性,每个端点有各自的端点号,包的地址字段包含要访问的端点号,usb主机通过端点号访问端点,从而实现和usb设备的通信。
3.1 usb设备的描述符
usb协议为usb设备定义了一套描述设备功能和属性的有固定结构的描述符,包括设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符;
3.1.1 设备描述符
每个usb设备只有一个设备描述符,描述了设备的一般信息,包括制造商标识号ID、产品序列号、所属设备类号、默认端点的最大包长度、配置描述符的个数:
1 struct usb_device_descriptor {
2 u8 bLength;
3 u8 bDescriptorType; /* 0x01 */
4 u16 bcdUSB;
5 u8 bDeviceClass;
6 u8 bDeviceSubClass;
7 u8 bDeviceProtocol;
8 u8 bMaxPacketSize0;
9 u16 idVendor;
10 u16 idProduct;
11 u16 bcdDevice;
12 u8 iManufacturer;
13 u8 iProduct;
14 u8 iSerialNumber;
15 u8 bNumConfigurations;
16 } __attribute__ ((packed));
3.1.2 配置描述符
每个usb设备可能有多个配置描述符,内容主要包括usb设备的供电方式、最大耗电量、此配置支持的接口个数等:
1 struct usb_configuration_descriptor {
2 u8 bLength;
3 u8 bDescriptorType; /* 0x2 */
4 u16 wTotalLength;
5 u8 bNumInterfaces;
6 u8 bConfigurationValue;
7 u8 iConfiguration;
8 u8 bmAttributes;
9 u8 bMaxPower;
10 } __attribute__ ((packed));
3.1.3 接口描述符
一个配置可能包含多个接口,一个接口表示一个设备具备的某一个功能,多个接口表示一个设备具备多个功能,我们编写的usb设备驱动程序是服务于一个接口的,也就是一个接口对应一个usb设备驱动程序:
1 struct usb_interface_descriptor {
2 u8 bLength;
3 u8 bDescriptorType; /* 0x04 */
4 u8 bInterfaceNumber;
5 u8 bAlternateSetting;
6 u8 bNumEndpoints;
7 u8 bInterfaceClass;
8 u8 bInterfaceSubClass;
9 u8 bInterfaceProtocol;
10 u8 iInterface;
11 } __attribute__ ((packed));
3.1.4 端点描述符
端点是usb主机和设备间通信的逻辑接口,每个设备都有一个端点0,在设备还没有分配地址时,主机通过这个接口和设备通信,一般功能端点都是单向的,也就是只能被主机写或者只能被主机读,但是这个端点0是双向的,并且没有端点描述符;端点描述符描述了数据的传输类型(控制传输、中断传输、批量传输、同步传输)、传输方向、数据包大小和端点号:
1 struct usb_endpoint_descriptor {
2 u8 bLength;
3 u8 bDescriptorType; /* 0x5 */
4 u8 bEndpointAddress;
5 u8 bmAttributes;
6 u16 wMaxPacketSize;
7 u8 bInterval;
8 } __attribute__ ((packed));
3.1.5 字符串描述符
字符串描述符是一个可选信息,描述了如制造商、设备名称、序列号等信息:
1 struct usb_string_descriptor {
2 u8 bLength;
3 u8 bDescriptorType; /* 0x03 */
4 u16 wData[0];
5 } __attribute__ ((packed));
3.2 usb主机和usb设备的通信
3.2.1 主机和设备通信流程
usb主机和设备的通信通过主机访问设备的端点实现,通信方式基于4种类型的包(令牌包、数据包、握手包、特殊包),包是USB信息传输的基本单元,包由5个字段组成:同步字段(SYNC)、包标识符字段(PID)、数据字段(数据字段由地址(设备地址和端点号)、frame number、Data构成)、CRC字段、结尾字段(EOP);
对于不同场景的通信任务,usb协议定义了4种传输方式:控制传输、中断传输、批量传输、同步传输,对应的,每个端点的传输类型都属于其中一种;
控制传输(双向):主要传输对设备的控制指令、设备状态查询及确认命令,用于连接时的设备枚举,不允许出错或丢失;
中断传输(单向):仅输入主机的少量数据,如鼠标;
批量传输(单向、双向):大批量数据的传输,实时性不强,但是要求不能出错,若出错应重新传输,用于U盘、打印机、数码相机等;
同步传输(单向、双向):连续的固定速率数据的传输,要求低延时传输,应开辟较大缓冲区,并确保低误码率。
因此,usb主机和usb设备的通信就是通过这4种传输方式实现。
每次传输都需要主机和设备互相收发多个不同的包实现,为了描述这个过程,还需要引入事务这个概念,setup事务、输入事务、输出事务:
setup事务:主机用来向设备发送控制命令,
1、主机向设备发送令牌信息包,告知设备主机要写数据;
2、主机将命令通过数据包发给设备;
3、设备向主机发送握手包确认收到数据;
输入事务:主机用来从设备读取数据,
1、主机向设备发送令牌信息包,告知设备主机要读数据;
2、设备向主机发送数据包;
3、主机向设备发送握手包确认收到数据;
输出事务:主机用来向设备发送数据,
1、主机向设备发送令牌信息包,告知设备主机要写数据;
2、主机向设备发送数据包;
3、设备向主机发送握手包确认收到数据;
比如,在设备枚举阶段,主机读取设备的配置描述符,需要使用控制传输访问设备的控制端点0,需要使用到3种事务,步骤如下:
1 /*
2 * 设备描述符读取步骤
3 * 使用控制传输读
4 */
5 1、设置事务(setup stage)
6 主机向设备写入获取设备描述符的命令,这个事务由3个数据包完成
7 令牌包(setup:OUT):告知设备主机要写数据
8 数据包(主机->设备):使用设备地址0向端点0写入获取描述符的命令
9 8字节命令字段:
10 1byte:bmRequestType
11 1byte:bRequest
12 2byte:wvalue
13 2byte:wIndex
14 2byte:wLength
15 握手包:设备向主机回复ACK
16
17 2、输入事务(data stage)
18 主机向设备发送IN方向的令牌包,设备将设备描述符发给主机,然后主机回复握手包给设备
19 令牌包(setup:IN):向设备告知要读数据
20 数据包(设备->主机):设备将描述符发给主机
21 握手包:主机向设备回复ACK
22
23 3、输出事务(status stage)
24 状态信息步骤,因为描述符有18字节,上面只读了16字节,所以设备所处的状态是等到主机读剩余2字节,但是主机不需要读这2字节,
25 因此发送空的写数据事务,用来复位设备的状态,以告知设备主机已经接收完数据
26 令牌包(setup:OUT):向设备告知要写数据
27 数据包(主机->设备):发送包,但是数据内容为空
28 握手包:设备向主机回复ACK
3.2.2 usb请求命令
usb协议定义了11种请求命令,命令由8个字节构成,命令封装在数据包的data字段发给usb设备,这8个字节命令格式为:
1 8字节命令字段:
2 1byte:bmRequestType
3 1byte:bRequest
4 2byte:wvalue
5 2byte:wIndex
6 2byte:wLength
11种命令分别是:
GET_STATUS、CLEAR_FEATURE、SET_FEATURE、SET_ADDRESS、GET_DESCRIPTOR、SET_DESCRIPTOR、GET_CONFIGURATION、SET_CONFIGURATION、GET_INTERFACE、SET_INTERFACE、SYNCH_FRAME;
厂商可以选择性支持部分命令,如下是dm9601支持的usb标准命令:
厂商除了支持标准usb命令,还可以定义自己的usb命令,如下是2条dm9601自定义的用于读写内部寄存器的命令:
四、usb驱动流程
本节总结uboot基于DM代码框架的usb驱动流程,大致内容如下:
设置usb控制器;
扫描usb控制器下挂的设备,usb hub;
设置usb hub;
扫描usb hub的所有port;
枚举port连接的usb设备;
调用usb设备驱动的probe函数,也就是dm9601 usb网卡驱动的probe函数;
4.1 设置usb控制器
这个阶段会设置usb phy的寄存器、设置usb控制器的寄存器,让usb控制器工作起来,可以发包扫描usb设备。
4.2 枚举usb root hub
首先,usb控制器使用设备地址0访问root hub的端点0,读取root hub的设备描述符,然后设置root hub的设备地址(每次枚举到一个设备,这个地址就增加1,也就是下一个枚举到的设备地址比root hub加1),然后选择一个默认配置,接着读取厂商、制造、序列号的字符串描述符;接着,设备驱动使用读取到的root hub的厂商ID匹配hub的驱动程序,从而调用相关的probe函数,对root hub进行相关设置;在相关probe函数里面会将hub所有的port都上电,接着会读取port的状态看该port是否有连接usb设备,如果有连接usb设备,就对这个usb设备进行枚举。
读取root hub的厂商ID、设置root hub的设备地址,用厂商ID查找hub的设备驱动程序,调用驱动程序的probe函数:
Root hub的前半部分probe没有实质性操作,只是一些数据结构的初始化:
Root hub的后半部分probe函数,执行uclass的uclass_post_probe_device函数,这个函数里面会下发控制消息给root hub,获取hub描述符,然后将root hub的每个port上电,然后读取port的状态判断是否连接usb设备,对连接的usb设备进行枚举:
对port上连接的usb设备进行枚举,和枚举root hub一样,首先会读取usb设备的设备描述符,设置usb设备的设备地址,然后用读到的厂商ID查找usb设备的驱动程序,接着调用该驱动程序的probe函数,这里是dm9601网卡:
Dm9601网卡驱动的probe函数,这个probe函数里面会解析端点信息保存到全局变量以便后面使用、设置接口、操作dm9601的寄存器进行网卡相关功能的操作:复位网卡、设置mac地址、读器件ID、power up phy等;
参考博客:
https://www.usbzh.com/article/detail-243.html
https://blog.csdn.net/snaking616/article/details/85759974
https://blog.csdn.net/qq_41483419/article/details/129009273
https://blog.csdn.net/gy794627991/article/details/123424120
https://blog.csdn.net/weixin_38878510/article/details/109028877
https://blog.csdn.net/ooonebook/article/details/53234020