Linux usb子系统子系统架构.docx
《Linux usb子系统子系统架构.docx》由会员分享,可在线阅读,更多相关《Linux usb子系统子系统架构.docx(20页珍藏版)》请在冰豆网上搜索。
Linuxusb子系统子系统架构
Linuxusb子系统:
子系统架构
一、USB协议基础知识
前序:
USB概念概述
USB1.0版本速度1.5Mbps(低速USB)USB1.1版本速度12Mbps(全速USB) USB2.0版本速度480Mbps(高速USB)。
USB分为主从两大体系,一般而言,PC中的USB系统就是作主,而一般的USB鼠标,U盘则是典型的USB从系统。
USB主控制器这一块,我们至少要开发出USB的主控制器与从控制器,鼠标是低速设备,所需的是最简单的一类从控制器。
主控制器则复杂得多,因为太过于复杂了,所以就形成了一些标准。
在一个复杂的系统中,标准的好处就是可以让开发者把精力集中在自己负责的一块中来,只需要向外界提供最标准的接口,而免于陷于技术的汪洋大海中。
USB主控制器主要有1.1时代的OHCI和UHCI,2.0时代的EHCI,这些标准规定了主控制器的功能和接口(寄存器的序列及功能),对我们驱动工程师而言,这样的好处就是只要你的驱动符合标某一标准,你就能轻而易举的驱动所有这个标准的主控制器。
要想把主控制器驱动起来,本来是一件很难的事情,估计全球的IT工程师没几个能有这样的水平,但有了标准,我们就可以轻松的占有这几个高水平的IT工程师的劳动成果。
主控制器和驱动有了,我们还需要USB协议栈,这就是整个USB系统的软件部分的核心(有的资料中直接把其称为USB核心),USB协议栈一方面向使用USB总线的设备驱动提供操作USB总线的API,另一方面则管理上层驱动传下来的的数据流,按USB主控制器的要求放在控制器驱动规定的位置,USB主控制器会调度这些数据。
我们这里用到了调度这个词,USB主控制器的调度其实和火车的调度CPU的调度有相似之处,物理上的通路只有一条,但USB中规定的逻辑上的通路却有许多条,有时一个设备就会占用几条逻辑通道,而USB系统中又会有多个设备同时运行。
这就好像是只有一条铁路线,但来来往往的火车却有许多,USB主控制器的作用就是调度这些火车,而USB协议栈的作用则向上层的USB设备驱动提供不同的车次。
有了以上的这些模块,才能为USB鼠标设计驱动,这一点上ps/2鼠标的驱动和USB鼠标的驱动结构基本一样,只不过我们的数据通路是USB总线。
USB系统甚至把设备驱动都给标准化了,只要是支持USB的主机,就可以支持任何一个厂商的USB鼠标,任何一个厂商的U盘,只要是被USB系统包函的设备,只要这些设备支持相应的标准,就无需重新设计驱动而直接使用。
下是简单的列出了USB设备类型,理想的情况USB系统要对这些设备作完整的支持,设备也必须符合USB规范中的要求。
1-audio:
表示一个音频设 备。
2-communication device:
通讯设备,如电话,moden等等。
3-HID:
人机交互设备,如键盘,鼠标等。
6-image图象设备,如扫描仪,摄像头等,有时数码相 机也可归到这一类。
7-打印机类。
如单向,双向打印机等。
8-mass storage海量存储类。
所有带有一定存储功能的都可以归到这一类。
如数码相机大多数都归这一类。
9-hub类。
11-chip card/smart card。
13--ContentSecurity
14--Video (Interface)
15--PersonalHealthcare
220--DiagnosTIcDevice
224--WirelessController (Interface)
239--Miscellaneous
254--ApplicaTIonSpecific (Interface)
255-vendor specific.厂家的自定义类,主要用于一些特殊的设备。
如接口转接卡等。
随着USB技术的发展,USB系统中的一些不足也逐渐被承认,OTG就是这种情况下的主要产物。
现在市面上有些设备(比如一些MP4)即能插上电脑当U盘使,也能被U盘插上读取U盘。
这样的设备在USB系统中是作主还是作从呢?
这就是OTG(On-The-Go),即可以作主也可以作从,传说中的雌雄同体。
这主要是为嵌入式设备准备的,因为USB是一种主从系统,不能支持点对点平等的传输数据,OTG正是在这种需求下产生的,OTG不仅支持控制器的主从切换,在一定层度上,也支持相同设备之间的数据交换。
1、USB的传输线结构
一条USB的传输线分别由地线、电源线、D+、D-四条线构成,D+和D-是差分输入线(抗干扰),它使用的是3.3V的电压,而电源线和地线可向设备提供5V电压,最大电流为500MA。
OTG的做法就是增来一个IDpin来判断设备是接入设备的是主还是从。
vbus主要是供电,D+/D-则是用来传输数据,就是我们前面所讲的主设备和从设备间唯一的一条铁路。
信号线名称
颜色
1
Vbus
红
2
D-
白
3
D+
绿
4
GNU
黑
shell (金属壳)
屏敝层
2、USB可以热插拔的硬件原理
USB主机是如何检测到设备的插入的呢?
首先,在USB集线器的每个下游端口的D+和D-上,分别接了一个15K欧姆的下拉电阻到地。
这样,在集线器的端口悬空时,就被这两个下拉电阻拉到了低电平。
而在USB设备端,在D+或者D-上接了1.5K欧姆上拉电阻。
对于全速和高速设备,上拉电阻是接在D+上;而低速设备则是上拉电阻接在D-上。
这样,当设备插入到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,结果就将差分数据线中的一条拉高了。
集线器检测到这个状态后,它就报告给USB主控制器(或者通过它上一层的集线器报告给USB主控制器),这样就检测到设备的插入了。
USB高速设备先是被识别为全速设备,然后通过HOST和DEVICE两者之间的确认,再切换到高速模式的。
在高速模式下,是电流传输模式,这时将D+上的上拉电阻断开。
3、USB主机控制器
USB主机控制器属于南桥芯片的一部分,通过PCI总线和处理器通信。
USB主机控制器分为UHCI(英特尔提出)、OHCI(康柏和微软提出)、 EHCI。
其中OHCI驱动程序用来为非PC系统上以及带有SiS和ALi芯片组的PC主办上的USB芯片提供支持。
UHCI驱动程序多用来为大多数其他PC主板(包括Intel和Via)上的USB芯片提供支持。
ENCI兼容OHCI和UHCI。
UHCI的硬件线路比OHCI简单,所以成本较低,但需要较复杂的驱动程序,CPU负荷稍重。
主机控制器驱动程序完成的功能主要包括:
解析和维护URB,根据不同的端点进行分类缓存URB;负责不同USB传输类型的调度工作;负责USB数据的实际传输工作;实现虚拟跟HUB的功能。
4、USB设备的构成
USB设备的构成包括了配置,接口和端点。
1. 设备通常具有一个或者更多个配置
2. 配置经常具有一个或者更多个接口
3. 接口通常具有一个或者更多个设置
4. 接口没有或者具有一个以上的端点
需要注意的是,驱动是绑定到USB接口上,而不是整个设备。
5、主控制怎么正确访问各种不同的USB设备
每一个USB设备接入PC时,USB总线驱动程序都会使用默认的地址0(仅未分配地址的设备可以使用)跟USB设备通信,然后给它分配一个编号,接在USB总线上的每一个USB设备都有自己的编号(地址),PC机想访问某个USB设备时,发出的命令都含有对应的编号(地址)就可以了。
USB总线驱动程序获取USB设置信息。
USB设备里都会有一个叫 EEPROM的东东,它就是用来存储设备本身信息的。
它与Flash虽说都是要电擦除的,但它可以按字节擦除,Flash只能一次擦除一个 block。
6、usb-firmware简易框架
usbfirmware主要工作是满足usb协议所定义的标准请求(usb协议第9章第4节),不同的firmware因为硬件不同而操作有所不同,但目的都是完成主控制器对设备的标准请求,大致框图如下:
7、USB传输事务
USB通信最基本的形式是通过一个名为端点(endpoint)的东西。
它是真实存在的。
端点只能往一个方向传送数据(端点0除外,端点0使用message管道,它既可以IN又可以OUT),或者IN,或者OUT。
除了端点0,低速设备只能有2个端点,高速设备也只能有15个IN端点和15个OUT端点。
主机和端点之间的数据传输是通过管道。
端点只有在device上才有,协议说端点代表在主机和设备端点之间移动数据的能力。
USB通信都是由host端发起的。
首先明确一点USB协议规定所有的数据传输都必须由主机发起。
所以这个传输的一般格式:
令牌包(表明传输的类型),数据包(实际传输的数据),握手包(数据的正确性)。
首先是由主机控制器发出令牌包,然后主机/设备发送数据包,甚至可以没有,最后设备/主机发送握手包,这么一个过程就叫做一个USB传输事务。
一个USB传输事务就实现了一次从主机和设备间的通讯。
USB的事务有:
OUT、IN、SETUP事务。
令牌包:
可分为OUT包、IN包、SetUp包和帧起始包,OUT包就是说明接下来的数据包的方向时从主机到设备。
数据包:
里面包含的就是我们实际要传输的东东了 。
握手包:
发送方发送了数据,接受方收没收到是不是该吱个声呀。
一个数据包里面包含有很多的域,里面包含了很多信息,一般有同步的域,数据包的核心信息的域,数据校验的域。
令牌包:
SYNC+PID+ADDR+ENDP+CRC5:
(同步)+(IN/OUT/SetUp)+(设备地址)+(设备端点)+(校验)
数据包:
分为DATA0包和DATA1包,当USB发送数据的时候,当一次发送的数据长度大于相应端点的容量时,就需要把数据包分为好几个包,分批发送,DATA0包和DATA1包交替发送,即如果第一个数据包是 DATA0,那第二个数据包就是DATA1。
SYNC+PID+DATA0/1+CRC5:
(同步)+(DATA0/1)+(数据)+(校验)。
但也有例外情况,在同步传输中(四类传输类型中之一),所有的数据包都是为DATA0,格式如下:
SYNC+PID+0~1023字节 +CRC16:
(同步)+(DATA0)+(数据)+(校验)。
握手包:
SYNC+PID:
(同步)+(HandShake)
8、USB协议的四种传输类型
因为usb支持的设备实在是太多,而且不同的设备对于传输数据各有各的要求和这就导致了我们需要不同的传输方式。
USB支持4种传输方式:
控制传输;批量传输;中断传输;实(等)时传输。
控制传输:
首先发送 Setup 传输事务,然后IN/OUT传输事务,最后是 STATUStransacTIon,向主机汇报前面SETUP 和 IN/OUT阶段的结果。
控制传输主要用于向设备发送配置信息、获取设备信息、发送命令道设备,或者获取设备的状态报告。
控制传输一般发送的数据量较小,当USB设备插入时,USB核心使用端点0对设备进行配置,另外,端口0与其他端点不一样,端点0可以双向传输。
批量传输:
由OUT事务和IN事务构成,用于大容量数据传输,没有固定的传输速率,也不占用带宽,当总线忙时,USB会优先进行其他类型的数据传输,而暂时停止批量转输。
批量传输通常用在数据量大、对数据实时性要求不高的场合,例如USB打印机、扫描仪、大容量存储设备、U盘等。
中断传输:
由OUT事务和IN事务构成,中断传输就是中断端点以一个固定的速度来传输较少的数据,USB键盘和鼠标就是使用这个传输方式。
这里说的中断和硬件上下文中的中断不一样,它不是设备主动发送一个中断请求,而是主机控制器在保证不大于某个时间间隔内安排一次传输。
中断传输对时间要求比较严格,所以可以用中断传输来不断地检测某个设备,当条件满足后再使用批量传输传输大量的数据。
等时传输:
由OUT事务和IN事务构成,有两个特殊地方,第一,在同步传输的IN和OUT事务中是没有握手阶段;第二,在数据包阶段所有的数据包都为DATA0。
等时传输同样可以传输大批量数据,但是对数据是否到达没有保证,它对实时性的要求很高,例如音频、视频等设备(USB摄像头,USB话筒)。
这4种传输方式由4个事务组成:
IN事务:
IN事务为host输入服务,当host需要从设备获得数据的时候,就需要IN事务。
OUT事务:
OUT事务为host输出服务,当host需要输出数据到设备的时候,就需要OUT事务。
SETUP事务:
SETUP事务为host控制服务,当host希望传输一些USB规范的默认操作的时候就需要使用setup事务。
SOF事务:
这个用于帧同步。
然后这4种事务又由3类包(token包,handshake包,data包)组成,每类又分几种:
in包:
in包用于指明当前的事务为in类型的。
out包:
out包用于指明当前事务为out类型的。
setup包:
setup包指明当前事务为setup类型的。
sof包:
sof包指明当前事务为setup类型的。
ack包:
ack握手包指明当前的事务的数据包传输是成功的。
nak包:
nak握手包指明当前设备忙,不能处理数据包,请主机稍后再次发送。
stall包:
stall握手包指明当前设备不能接受或者传输数据,表示一个严重的错误。
data0包:
该数据包的类型为0。
data1包:
该数据包的类型为1。
下图是一个USB鼠标插入Linux系统时完整的枚举过程,一共发生了11次传输,每次传输包括几个事务,每个事务又包括几个包,每个包包括几个域。
这里有一个概念需要注意,这里的中断传输与硬件中断那个中断是不一样的,这个中断传输实际是靠USBhostcontrol轮询usbdevice来实现的,而USBhostcontrol对于CPU则是基于中断的机制。
拿USB鼠标为例,USBhostcontrol对USB鼠标不断请求,这个请求的间隔是很短的,在USBspecTable9-13端点描述符中的bInterval域中指定的,当鼠标发生过了事件之后,鼠标会发送数据回host,这时USBhostcontrol中断通知CPU,于是usb_mouse_irq被调用,在usb_mouse_irq里,就可以读取鼠标发回来的数据,当读完之后,驱动再次调用usb_submit_urb发出请求,就这么一直重复下去,一个usb鼠标的驱动也就完成了。
下面是USB鼠标中断传输图,可以看到USBhostcontrol向usbdevice发送了IN包,没有数据的时候device回复的是NAK,有数据的时候才向hostcontrol发送DATA包。
9、USB设备被识别的过程
当USB设备插上主机时,主机就通过一系列的动作来对设备进行枚举配置。
1、接入态(Attached):
设备接入主机后,主机通过检测信号线上的电平变化来发现设备的接入;
2、供电态(Powered):
就是给设备供电,分为设备接入时的默认供电值,配置阶段后的供电值(按数据中要求的最大值,可通过编程设置)
3、缺省态(Default):
USB在被配置之前,通过缺省地址0与主机进行通信;
4、地址态(Address):
经过了配置,USB设备被复位后,就可以按主机分配给它的唯一地址来与主机通信,这种状态就是地址态;
5、配置态(Configured):
通过各种标准的USB请求命令来获取设备的各种信息,并对设备的某此信息进行改变或设置。
6、挂起态(Suspended):
总线供电设备在3ms内没有总线动作,即USB总线处于空闲状态的话,该设备就要自动进入挂起状态,在进入挂起状态后,总的电流功耗不超过280UA。
10、标准的USB设备请求命令
USB设备请求命令是在控制传输的第一个阶段:
setup事务传输的数据传输阶段发送给设备的。
标准USB设备请求命令共有11个,大小都是8个字节,具有相同的结构,由5个字段构成。
通过标准USB准设备请求,我们可以获取存储在设备EEPROM里面的信息;知道设备有哪些的设置或功能;获得设备的运行状态;改变设备的配置等。
标准USB准设备请求 = bmRequestType
(1) + bRequest
(2) + wvalue
(2) + wIndex
(2) + wLength
(2)
bmRequestType:
[7bit]=0主机到设备; 1设备到主机
[6-5bit]=00标准请求命令; 01类请求命令; 10用户定义命令; 11保留
[4-0bit]=00000 接收者为设备; 00001 接收者为接口; 00010 接收者为端点; 00011 接收者为其他接收者; 其他 其他值保留
bRequest:
0) 0GET_STATUS:
用来返回特定接收者的状态
1) 1CLEAR_FEATURE:
用来清除或禁止接收者的某些特性
2) 3SET_FEATURE:
用来启用或激活命令接收者的某些特性
3) 5SET_ADDRESS:
用来给设备分配地址
4) 6GET_DEscriptOR:
用于主机获取设备的特定描述符
5) 7SET_DEscriptOR:
修改设备中有关的描述符,或者增加新的描述符
6) 8GET_CONFIGURATION:
用于主机获取设备当前设备的配置值、
7) 9SET_CONFIGURATION:
用于主机指示设备采用的要求的配置
8) 10GET_INTERFACE:
用于获取当前某个接口描述符编号
9) 11SET_INTERFACE:
用于主机要求设备用某个描述符来描述接口
10) 12SYNCH_FRAME:
用于设备设置和报告一个端点的同步
wvalue:
这个字段是 request 的参数,request 不同,wValue就不同。
wIndex:
wIndex,也是request 的参数,bRequestType指明 request 针对的是设备上的某个接口或端点的时候,wIndex 就用来指明是哪个接口或端点。
wLength:
控制传输中 DATAtransaction 阶段的长度。
二、Linux USB系统架构
这个是USB系统的拓扑图,4个部分构成:
USB主机控制器,根集线器,集线器,设备。
其中RootHub与USB主机控制器是绑定在一起的。
在机箱的尾部面板上,物理上存在一,二或四个USB端口。
端口可以用来连接一个普通设备或者一个hub,hub是一个USB设备,可以用来扩展连接USB设备的端口数量。
最大连接USB设备数量是减去连在总线上的hub数量(如果有50个hub,那么最多77(=127-50)个设备能够连接),剩下的就是能够连接USB设备的数量。
Hub总是高速的,如果一个hub是自供电的,那么任何设备都能够附着到上面。
但是如果hub是总线供电的,那么仅仅低供电(最大100mA)设备能够附着到上面,一个总线供电的hub不应该连接到另一个总线供电的hub-你应该在总线供电和自供电间交替.
通常情况下主机控制器的物理端口由一个虚拟的roothub脸管理。
这个hub是有主机控制器(hostcontroller)的设备驱动虚拟的,用来统一管理总线拓扑,因此USB子系统的驱动能够用同样的方法管理每个端口。
USB通信都是由host端发起的。
USB设备驱动程序分配并初始化一个URB发给USBCore,USBCore改一改,发给USB主机控制器驱动,USB主机控制器驱动把它解析成包,在总线上进行传送。
USBCore是由内核实现的,其实也就是把hostcontroldriver里的功能更集中的向上抽象了一层,它是用来对最上层的USB设备驱动屏蔽掉hostcontrol的不同。
USB通信最基本的形式是通过一个名为端点(endpoint)的东西。
它是真实存在的。
端点只能往一个方向传送数据(端点0除外,端点0使用message管道,它既可以IN又可以OUT),或者IN,或者OUT(前面已经介绍过)。
除了端点0,低速设备只能有2个端点,高速设备也只能有15个IN端点和15个OUT端点。
主机和端点之间的数据传输是通过管道。
端点只有在device上才有,协议说端点代表在主机和设备端点之间移动数据的能力。
Linux系统下的usb部分分为四个部门或者叫做四大家族,他们是host控制器驱动、hub驱动、usbcore、设备类驱动,他们共同配合着完成了对usb设备的访问操作。
枚举和设备描述符
每当一个USB设备附着到总线上,它将会被USB子系统枚举.也就是分配唯一的设备号(1-127)然后读取设备描述符.描述符是一个包含关于设备的信息和属性的数据结构.USB标准定义了一个描述符层次结构,下图所示:
标准描述符
设备描述符:
描述USB设备的大概信息,其中包括适用于设备的全局信息,所有设备的配置。
一个USB设备只有一个设备描述符。
配置描述符:
描述了特定的设备配置信息。
一个USB设备可以有一或多个配置描述符。
每个配置有一个或多个接口(interface),并且每个接口有零或多个端点(endpoint)。
一个端点在一个单独的配置下,是不和其他的接口共享的,但是一个单独的接口对于同一个端点能够有几种可选的配置。
端点可以没有限制的在一部分不同的配置下的接口间共享。
配置仅仅能够通过标准的控制传输set_configuration来激活。
不同的配置能够用来全局配置信息,例如供电消耗。
接口描述符:
描述了一个配置内的特定接口。
一个配置提供一个或多个接口,每个接口带有零个或多个端点描述符描述了在配置内的唯一配置。
一个可以包含可选的配置的接口使得配置好的端点和/或他们的特性能够多种多样。
默认的接口设置总是设置为零。
可替换的设置能够在标准控制传输的set_interface来选择一个。
例如一个多功能设备带有话筒的摄像头,可以有三种可用的配置来改变分配在总线上的带宽。
CameraactivatedMicrophoneactivatedCameraandmicrophoneactivated
端点描述符:
包含主机用来决定每个端点带宽的信息。
一个端点象征一个USB设备的逻辑数据源或接收端(logicdatasourceorsink)。
端点零是用来所有的控制传输并且该端点没有设备描述符。
USBspec交替使用pipe和endpoint术语。
字符串描述符:
是可选项,提供了unicode编码的额外的可读信息。
他们可以是厂商和设备名称或序列号。
设备类型
标准的设备和接口描述符包含有关分类的内容:
class, sub-class和protocol。
这些字段主机可以用来设备或接口和驱动联系。
依赖于分类说明是如何指定的?
对于class字段和接口描述符的合法字段是由USBDeviceWorkingGroup来定义的。
在ClassSpecification中将设备或接口分组归类并指定特性,这样就使得主机开发软件能够基于这个类别进行管理多种多样的实现。
这样的主机软件通过设备中的描述信息将操作方法绑定到指定的设备。
一个类别规格作为所有的该类别的设备或接口的最小操作框架服务。
(PS:
也就是说,所有该类别的设备或接口,都是以类别规格定义为接口框架。
)
人机接口设备
HID分类,主要是包含人们控制计算机系统的设备。
典型的HID分类设