1. Linux USB驱动软件框架
应用程序有两种访问硬件的途径:通过设备驱动程序来访问和跳过设备驱动程序(直接使用host驱动程序)来访问。
当直接使用Host驱动程序时,可以调用libusb库中已经封装好的函数接口。
2. USB电气信号
一个USB设备,可能兼容低速、全速,也可能兼容全速、高速。但不会同时兼容低速、高速。
USB2.0设备由4根线组成,其中包括Vcc, GND, D+, D-。用于传输传输数据的只有两根线D+和D-。两根线的通过高低电平,可以组合成4种状态(00, 01, 10, 11)。根据USB2.0协议,对于低速和全速设备(高速设备类似)主要有四种状态,差分1,差分0,单端1,单端0。后面都是以这四种状态,根据需要产生的别名。
USB主机是如何检测到设备的插入?
USB集线器的每个下游端口的D+和D-上,分别接了一个15KΩ的下拉电阻到地,在端口悬空时,就被这两个下拉电阻拉到了低电平。而在USB设备端,在D+和D-端接了1.5K欧姆的上拉电阻。对于全速和高速设备,上拉电阻接在D+上,对于低速设备,上拉电阻接在D-上。当设备插入到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,就将差分数据线中的一条拉高了。集线器检测到这个状态后,就报告给USB主控制器(或者通过他上一层的集线器报告给USB主控制器),这样就检测到设备的插入了。USB告诉设备首先被识别为USB全速设备,然后通过HOST和DEVICE两者之间的确认,再切换到高速模式。
当USB设备插入时,USB主机控制器的D+或D-被拉高,在主机控制器端会产生一个中断发现一个新设备并通过端点0给新设备分配一个地址和获取USB设备的设备描述符,解析设备描述符并通过device_add()将其添加到usb_bus_type链表中,并且匹配链表上的driver程序,匹配成功后调用driver的probe函数,这部分过程类似Platform平台总线驱动。
对于低速设备,在连接期间D-管脚一直是高电平,当hub检测到D-被拉低,说明设备已经断开连接。
对于全速设备,在连接期间D+管脚一直是高电平,当hub检测到D+被拉低,说明设备已经断开连接。
对于高速设备,设备刚刚插入时,是通过将D+拉高来识别的,D+被拉高可认为是全速设备或者是高速设备,那么如何判断是否是高速设备呢?(速率识别)
Hub给Device发出复位信号,如果Device支持高速模式,就会回复一个K信号,Hub收到K信号后,如果自身也支持高速模式,就会发出一系列的KJ信号,Device收到后就知道Hub也支持高速模式,然后就会把自身D+的上拉电阻断开。
当高速设备断开后,Hub发出的信号,得到的反射信号法无衰减,Hub监测到这些信号以后就知道设备已经断开(此处涉及到比较深的与阻抗匹配相关的硬件知识)。
3. USB数据包
SOP(Start of Packet):起始信号;
SYNC:同步信号;
EOP(End of Packet):终止信号
上图中体现出的一种传输方式为,A要给B发送数据,只有一条线,那么就先发送一个同步信号,B根据同步信号计算出波特率,然后根据波特率设置采样时间,从而达到数据传输的目的。
在USB中就是用了这种思想传输数据,但是USB是使用D+与D-两根线的差分信号来表示逻辑0和逻辑1。
反向不归零编码:波形发生变化表示传输的是0,不发生变化表示传输的是1。
对于要发送很多个数据1的时候,理论上会保持很多个周期T波形不变,这个时候如果双方晶振误差等原因,就容易造成1的个数解析误差,所以在连续发送6个1后,就会发送一个0,即强制翻转发送信号(位填充技术)。
USB传输数据就是使用这种:反向不归零编码+位填充技术。