一、USB的一些基本概念
-
管道(Pipe) 是主机和设备端点之间数据传输的模型,共有两种类型的管道:无格式的
流管道(Stream Pipe)和有格式的信息管道(Message Pipe)。任何USB 设备一旦上电就存在
一个信息管道,即默认的控制管道,USB 主机通过该管道来获取设备的描述、配置、状态,并
对设备进行配置。 -
端点(Endpoint) 是USB 设备中的可以进行数据收发的最小单元,支持单向或者双向的数据传
输。设备支持端点的数量是有限制的,除默认端点外低速设备最多支持2 组端点(2 个输入,2
个输出),高速和全速设备最多支持15 组端点。 -
接口(Interface) 应用软件通过和设备之间的数据交换来完成设备的控制和数据传输。通常
需要多个管道来完成数据交换,因为同一管道只支持一种类型的数据传输。用在一起来对设备进
行控制的若干管道称为设备的接口. -
设备和端点之间关系: 一个USB 设备可以包括若干个端点,不同的端点以端点编号和方向区分。
不同端点可以支持不同的传输类型、访问间隔以及最大数据包大小。除端点0 外,所有的端点只支
持一个方向的数据传输。端点0 是一个特殊的端点,它支持双向的控制传输。管道和端点关联,和
关联的端点有相同的属性,如支持的传输类型、最大包长度、传输方向等。 -
描述符(Descriptor) 描述设备的属性(Attributes). 它本身是一个数据结构, 第一个字节表示
描述符的大小(字节数), 第二个字节表示描述符的类型(Type). 描述符的种类有:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OH40HxS-1635519762323)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024907829.png)]
- 设备描述符(Device), 描述一个设备的一般信息.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5R2ZjWIj-1635519762324)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024907255.png)] - 设备修饰描述符(Device_Qualifier), 描述一个高速设备在其它速度下该如何变化的信息.
- 配置描述符(Configuration), 描述一个特定的设备配置, 如接口的数目等. 一个USB设备有一个或多个配置描述符. 每个配置有一个或多个接口并且每个接口有0个或多个端点.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JkB3AUZo-1635519762325)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024908442.png)] - 其它速度配置描述符(Other_speed_configuration), 描述高速设备在其它可能的速度下的
一个配置. - 接口描述符(Interface), 描述一种配置中的一个特定的接口.
- 端点描述符(Endpoint), 描述主机需要的去决定端点所需带宽的信息. 这个描述符只能附加在GetDescriptor()或GetDescriptor()请求中传送, 不能单独传送. 端点0没有此描述符.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fewnmTJt-1635519762326)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024908675.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hGob3BIf-1635519762327)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024908690.png)] - 字符串描述符(String), 第0个字符串描述符指定设备支持的语言, 其它的描述符则各包含
一个UNICODE字符串. 设备描述符, 配置描述符 和 接口描述符可能会包含字符串描述符.
- USB设备请求(USB Device Request) 请求是从主机通过控制管道发送到设备.
标准的设备请求有:
- Clear Feature
- Get Configuration
- Get Descriptor
- Get Interface
- Get Status
- Set Address
- Set Configuration
- Set Descriptor
- Set Feature
- Set Interface
- Synch Frame
二、USB3.0系统拓扑结构
系统是最多只能有7层的树状结构
最多只能支持127个设备和Hub
Host+RootHub永远是在第一层
复合(Compound)设备一般占两层
功能设备不能作为非叶节点, 只有Hub才可以
USB3.0 Hub其实包含了一个USB2的Hub和一个SuperSpeed Hub
三、 USB3.0的重要特性:
- 增加了一个重要的数据传输速率
- 点对点方式传输包, 使活动链路数目达到最少
- 异步方式的通知功能, 去除了轮询方式的必要
- 基于链路级的电源管理, 这是总线结构的基础设计
- 向后兼容USB2.0, 驱动级和物理层级别上都达到了兼容的目的
四、USB3.0与USB2.0的区别
-
数据传输速率, 3.0是SuperSpeed 5.0Gbps,
2.0是 1.5Mbps, 12Mbps或480Mbps -
数据接口, 3.0是全双工,独立于USB 2.0信号的四路差分信号,支持同时双向数据传输
2.0是半双工,双路差分信号, 单向数据传输, 需要事先协商好总路线的传输方向 -
信号线数目, 3.0是4路SuperSpeed数据线, 2路HighSpeed数据线和2路电源及地线
2.0是2路LS/FS/HS数据线, 2路电源及地线 -
总线事务协议, 3.0是主机主导的异步方式的传输流量控制, 包传输是能显式地进行路由
2.0是主机主导的轮询方式的传输流量控制, 包传输是通过广播方式到所有设备 -
电源管理, 3.0是多级别的链路电源管理, 支持Idle, sleep和suspend状态
2.0是在端口级进行管理, 可以在entry/exit上有两种级别的挂机状态 -
总线电源, 3.0是和USB 2.0差不多, 只是未配置的电源有50%的增幅, 已配置的电源有80%的增幅
-
主机控制器,3.0用的是xHCI,2.0则是EHCI。xHCI中提供了虚拟化技术支持。
五、USB3.0电源状态
- U0, Link active
- U1, Link idle – fast exit. 退出延时us级
- U2, Link idle – slow exit. 退出延时us-ms级
- U3, Link suspend. 无时钟信号, 退出延时us-ms级
六、USB3.0数据包类型
- Link Management Packets, 链路管理包, 仅发生在两个相连的端口之间,主要是用来进行链路管理
- Transaction Packets, 事务包, 发生在设备和主机之间, 用来控制数据包的流量, 配置设备和Hubs. 它没有数据
- Data Packets, 数据包, 发生在设备和主机之间. 它包括两部分:包头和实际数据. 其中数据部分还包括一个32位的CRC校验码来保证数据的完整性.
- Isochronous Timestamp Packets, 同步时间戳包, 它是唯一的多播方式发送的. 发送方向是从主机到所有U0状态的设备.
七、USB传输类型
1. 控制传输(Control Transfers)
控制传输是一种可靠的双向传输,一次控制传输可分为三个阶段。
第一阶段为从HOST 到Device 的SETUP 事务传输,这个阶段指定了此次控制传输的请求类型;
第二阶段为数据阶段,也有些请求没有数据阶段;
第三阶段为状态阶段,通过一次IN/OUT 传输表明请求是否成功完成。
控制传输通过控制管道在应用软件和Device 的控制端点之间进行,控制传输过程中传输的数据是
有格式定义的,USB 设备或主机可根据格式定义解析获得的数据含义。其他三种传输类型都没有格式定义。
控制传输对于最大包长度有固定的要求。对于高速设备该值为64Byte;对于低速设备该值为8;全速设备
可以是8 或16 或32 或64。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggQAbtj4-1635519762327)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024907614.png)]
2. 批量传输(Bulk Transfers)
批量传输是一种可靠的单向传输,但延迟没有保证,它尽量利用可以利用的带宽来完成传输,适合数据量比较大的传输。
低速USB 设备不支持批量传输,高速批量端点的最大包长度为512,全速批量端点的最大包长度可以为8、16、32、64。
批量传输在访问USB 总线时,相对其他传输类型具有最低的优先级,USB HOST 总是优先安排其他类型的传输,
当总线带宽有富余时才安排批量传输。高速的批量端点必须支持PING 操作,向主机报告端点的状态,NYET
表示否定应答,没有准备好接收下一个数据包,ACK 表示肯定应答,已经准备好接收下一个数据包。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsxxXdY6-1635519762328)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024907113.png)]
3. 中断传输(Interrupt Transfers)
中断传输是一种轮询的传输方式,是一种单向的传输,HOST 通过固定的间隔对中断端点进行查询,若有
数据传输或可以接收数据则返回数据或发送数据,否则返回NAK,表示尚未准备好。中断传输的延迟有保
证,但并非实时传输,它是一种延迟有限的可靠传输,支持错误重传。
对于高速/全速/低速端点,最大包长度分别可以达到1024/64/8 Bytes。高速中断传输不得占用超过80%的
微帧时间,全速和低速不得超过90%。中断端点的轮询间隔由在端点描述符中定义,全速端点的轮询间隔可
以是1255mS,低速端点为10255mS,高速端点为(2interval-1)*125uS,其中interval 取1到16 之间的值。
除高速高带宽中断端点外,一个微帧内仅允许一次中断事务传输,高速高带宽端点最多可以在一个微帧内进
行三次中断事务传输,传输高达3072 字节的数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XF4mr8rr-1635519762329)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024907854.png)]
4. 同步传输(Isochronous Transfers)
同步传输是一种实时的、不可靠的传输,不支持错误重发机制。只有高速和全速端点支持同步传输,高速同步端
点的最大包长度为1024,低速的为1023。
除高速高带宽同步端点外,一个微帧内仅允许一次同步事务传输,高速高带宽端点最多可以在一个微帧内进行三
次同步事务传输,传输高达3072 字节的数据。全速同步传输不得占用超过80%的帧时间,高速同步传输不得占用
超过90%的微帧时间。
同步端点的访问也和中断端点一样,有固定的时间间隔限制。
在主机控制器和USB HUB 之间还有另外一种传输——分离传输(Split Transaction),它仅在主机控制器和HUB 之间执行,通过分离传输,可以允许全速/低速设备连接到高速主机。分离传输对于USB 设备来说是透明的、不可见的。
八、 OTG协议
OTG设备采用Mini-AB插座,相对于传统的USB数据线,Mini-AB接口多了一根数据线ID,ID线是否接入将Mini-AB接口分为Mini-A和Mini-B接口两种类型。在OTG设备之间数据连接的过程中,通过OTG数据线Mini-A和Mini-B接口来确定OTG设备的主从:接入Mini-A接口的设备默认为A设备(主机设备);接入Mini-B接口的设备,默认为B设备(从设备)。
A设备和B设备无需交换电缆接口,即可通过主机交换协议(HNP)实现A、B设备之间的角色互换。同时,为了节省电源,OTG允许总线空闲时A设备判断电源。此时,若B设备希望使用总线,可以通过会话请求协议(SRP)请求A设备提供电源。
8.1 HNP(主机交换)协议
当Mini-A接口接入A设备并确定A设备为主机时;若B设备希望成为主机,则A设备向B设备发送SetFeature命令,允许B设备进行主机交换。B设备检测到总线挂起5ms后,即挂起D+并启动HNP,使总线处于SE0状态。此时A设备检测到总线处于SE0状态,即认为B设备发起主机交换,A设备进行响应。待B设备发现D+线为高电平而D-线为低电平(J状态),表示A设备识别了B设备的HNP请求。B设备开始总线复位并具有总线控制权,主机交换协议完成。
8.2 SRP(会话请求)协议
对于主机,要求能响应会话请求;对于设备,仅要求能够发起SRP协议。OTG设备,不仅要求发起SRP,而且还能响应SRP请求。
SRP分为数据线脉冲调制和电压脉冲调两种方式,B设备发起SRP必须满足以下两个条件:
1) B设备检测到A设备低于其有效的电压阈值,同时B设备低于有效的电压阈值。
2) B设备必须检测到D+和D-数据线至少在2ms的时间内低于有效阈值,即处于SE0状态。
数据线脉冲调制会话请求:B设备必须等到满足以上两个条件后,将数据线接入上拉电阻一定的时间,以备A设备过滤数据线上的瞬间电压。与此同时,B设备上拉D+以便于在全速模式下进行初始化操作。A设备在检测到D+变为高电平或D-变为低电平时产生SRP指示信号。
Vbus脉冲调制会话请求:B设备同样需等待满足上述两个初始化条件,然后B设备通过对电容充电以提高总线电压,待达到总线上的电压阈值,唤醒A设备。在充电过程中,一定要保证充电的电压峰值在一定的范围以避免烧坏A设备。
3. USB驱动架构
USB驱动架构如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vz9ok0ed-1635519762329)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024911989.png)]
3.1 USB主机端驱动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oTevXc87-1635519762330)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024912570.png)]
USB核心(USBD)是整个USB驱动的核心部分,从上图可知,一方面USBD对接收到USB主机控制器的数据进行处理,并传递给上层的设备端驱动软件;同时也接收来自上层的非USB格式数据流,进行相应的数据处理后传递给USB主机控制器驱动。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jBSMRmBs-1635519762330)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024912800.png)]
USB数据传输都以URB(USB Request Block)请求、URB生成、URB递交、URB释放为主线。从上图可知,当加载控制器驱动之后,注册根据集线器,hub和hcd驱动成为一个整体。接着,主机通过控制传输获取设备的控制描述符等信息,接着详述整个控制传输的流程。usb_submit_urb依据是否连接到根集线器来决定调用urb_enqueue或rh_urb_enqueue函数。
USB从设备通过集线器或根集线器连接到USB主机上。比如:主机通过根集线器与外界进行数据交互,根集线器通过探测数据线状态的变化来通知USB主机是否有USB外围设备接入。
在主机端控制器驱动加载的过程中,注册了根集线器,然后匹配了相应的hub驱动程序,同时完成了对Hub的轮询函数和状态处理函数的设置。这样,一旦hub集线器的状态发生变化,就会产生相应的中断,主机端控制器就会执行相应的中断处理函数,下图为hub驱动程序的流程图。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1hAPoJRy-1635519762331)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024920893.png)]
USB Core中的usb_init()函数中完成了对hub线程(khubd,在usb_hub_init函数中真正地创建)的创建,然后完成相应设备的探测。主机端控制器驱动进行探测时,将hub驱动和主机端控制器驱动结合在一起,相互之间完成调用。 相对于大容量存储设备与主机之间通过控制/批量传输,集线器与主机之间通过中断/控制方式完成数据交互。
3.2 USB设备端驱动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tValuejY-1635519762331)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024920442.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8GHZvppK-1635519762332)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024920220.png)]
从上图可知,设备端驱动包含两部分:
1) 底层设备控制器驱动
2) 上层大容量存储类驱动
3.2.1 设备控制器驱动
USB设备控制器驱动主要实现Gadget API定义的函数和中断服务函数,可按功能划分为:API函数实现模块和中断处理模块。
API函数主要实现Gadget API定义的函数功能,如结构体usb_ep_ops和usb_gadget_ops中的函数、usb_gadget_register_driver函数。这些函数是供Gadget Driver调用。
中断处理模块主要处理设备控制器产生的各种中断,包括端点中断、复位、挂起等中断。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rUKKHYMx-1635519762332)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024926681.png)]
上图为设备端控制器基本架构,主要完成了Gadget驱动和控制器驱动绑定、usb_gadget_register_driver注册。
3.3 OTG驱动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rAg7mVBY-1635519762333)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024926525.png)]
OS_FS: 文件系统
USBD: USB核心
HCD: 主机控制器驱动
UDC: 设备端控制器驱动
OTG设备支持HNP和SRP协议。OTG设备通过USB OTG电缆连接到一起,其中接Mini-A接口的设备为A设备,默认为主机端,Mini-B接口的设备默认为B设备。当A、B设备完成数据交互之后,A、B设备之间的USB OTG电缆进入挂起状态,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Xl86Ca4-1635519762333)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024926215.png)]
当B设备写入b_bus_req,向A设备发起HNP请求。待A设备响应之后,A设备发送a_set_b_hnp_en,B设备响应之后即进入主机状态,同时发送请求使用A设备set_device,这样A、B设备完成主从交换。
4. USB 传输流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLftzgwD-1635519762334)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024926952.png)]
4.1 USB初始化过程
USB驱动作为一个系统,集成了众多的驱动模块,注册过程非常复杂。从USB系统的角度来说,USB主机驱动主要包含:
-
USB核驱动
-
主机控制器驱动
-
集线器驱动
驱动的加载执行流程如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjKaqkvM-1635519762334)(http://2.eewimg.cn/news/uploadfile/2015/0821/20150821024930539.png)]
USB初始化过程
4.1.1 USB Core的初始化
USB驱动从USB子系统的初始化开始,USB子系统的初始化在文件driver/usb/core/usb.c
[cpp] view plaincopy
subsys_initcall(usb_init);
module_exit(usb_exit); subsys_initcall()是一个宏,可以理解为module_init()。由于此部分代码非常重要,开发者把它看作一个子系统,而不仅仅是一个模块。USB Core这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块。在Linux中,像这样一个类别的设备驱动被归结为一个子系统。subsys_initcall(usb_init)告诉我们,usb_init才是真正的初始化函数,而usb_exit将是整个USB子系统结束时的清理函数。
4.1.2 主机控制器的初始化及驱动执行(以EHCI为例)
module_init(otg_init); 模块注册static init __init otg_init(void);platform_driver_register(); 平台注册static int __init otg_probe(struct platform_device *pdev); 探测处理函数reg = platform_get_resource(pdev, IORESOURCE_MEM, 0); 获取寄存器信息data = platform_get_resource(pdev,IORESOURCE_MEM, 1); 获取内存信息irq = platform_get_irq(pdev,0); 获取中断号usb_create_hcd(&otg_hc_driver, &pdev->dev, pdev->dev.bus_id);
分配和初始化HCD结构体。对设备数据空间进行分配,初始化计数器、总线、定时器、hcd结构体各成员值。
ret = usb_add_hcd(hcd,irq,SA_INTERRUPT);
完成HCD结构体的初始化和注册。申请buffer,注册总线、分配设备端内存空间,向中断向量表中申请中断,注册根集线器,对根集线器状态进行轮询。
4.1.3 注册集线器
register_root_hub(hcd);
在USB系统驱动加载的过程中,创建了集线器的线程(khubd),并且一直查询相应的线程事务。HCD驱动中,将集线器作为一个设备添加到主机控制器驱动中,然后进行集线器端口的初始化。在USB主机看来,根集线器本身也是USB主机的设备。USB主机驱动加载完成之后,即开始注册根集线器,并且作为一个设备加载到主机驱动之中。
USB主机和USB设备之间进行数据交互,USB设备本身并没有总线控制权,U盘被动地接收USB主机发送过来的信息并做出响应。USB主机控制器与根集线器构成了主机系统,然后外接其它的USB设备。
为了更好地探测到根集线器的状态变化,USB主机控制器驱动增加了状态轮询函数,以一定的时间间隔轮询根集线器状态是否发生变化。一旦根集线器状态发生变化,主机控制器就会产生相应的响应。
USB主机和USB设备之间的数据传输以URB(USB Request Block)的形式进行。
4.2 URB传输过程
USB初始化过程中,无论是主机控制器驱动还是根集线器驱动,都是通过URB传输获取设备信息。
4.2.1 申请URB
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
为urb分配内存并执行初始化。
4.2.2 初始化URB
初始化具体的urb包
static inline void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context) static inline void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, unsigned char *setup_packet, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context)
static inline void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context, int interval)
不同的传输模式下,驱动为之申请不同的URB。其中,Linux内核只支持同步传输外的三种传输事件,ISO事务需要手工进行初始化工作。控制传输事务、批量传输事务、中断传输事务API如上所示。
三种事务传输模式下的URB初始化函数有很多相似之处,主要参数含义如下:
• urb: 事务传输中的urb
• dev: 事务传输的目的设备
• pipe: USB主机与USB设备之间数据传输的通道
• transfer_buffer: 发送数据所申请的内存缓冲区首地址
• length: 发送数据缓冲区的长度
• context: complete函数的上下文
• complete_fn: 调用完成函数
• usb_fill_control_urb()的setup_packet: 即将被发送的设备数据包
• usb_fill_int_urb()的interval: 中断传输中两个URB调度的时间间隔
4.2.3 提交URB
URB初始化完成之后,USBD开始通过usb_start_wait_urb()提交urb请求(它调用usb_submit_urb来真正的发送URB请求),添加completition函数。接下来,从message.c传到主机控制器(hcd.c),开始真正的usb_hcd_submit_urb()。此时,根据是否为根集线器,进入不同的工作队列。
usb_start_wait_urb->usb_submit_urb->usb_hcd_submit_urb
a) root_hub传输
若为root hub,将调用rh_urb_enqueue(),共有两种传输事务(控制传输和中断传输
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{ if (usb_endpoint_xfer_int(&urb->ep->desc)) // 中断传输 return rh_queue_status (hcd, urb); if (usb_endpoint_xfer_control(&urb->ep->desc)) // 控制传输 return rh_call_control (hcd, urb); return -EINVAL;
}
b) 非root_hub传输
对于非常root_hub传输,它调用:
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
c) 批量传输
root_hub本身没有批量传输流程,按照控制传输流程,控制传输最终要通过switch语句跳转到Bulk-Only传输流程中。