注意
- 对于物理特性仅做简单说明
- 主要是针对 USB 2.0 规范的第九章、第十章和第十一章。之前章节见后续见 第一部分
- 下面的举例报文为使用Bus Hound监听的U盘插入时的报文,报文见后文附件。
关于USB 2.0
在USB官方网站( http://www.usb.org/ )包含了我们必需的所有的USB协议规范。目前官网最新规范为USB 3.2。默认打开官网的Document菜单,显示的就是USB 3.2的相关规范文档,在Document菜单下有USB2.0相关规范。USB2.0 的下载页面为http://www.usb.org/developers/docs/usb20_docs/。
其中USB规范定义了各种USB Class,具体看见http://www.usb.org/developers/docs/devclass_docs/。该页面下面就是每个类对应的文档。
USB设备架构
USB 设备第一次连接到主机时, 要接收主机枚举( Enumeration) 和配置(Configuration) ,目的是让主机知道设备功能、是哪一类的USB 设备、占用多少资源、使用了哪些传输方式以及传输的数据量等等。只有主机完全确认了这些信息后, 设备才能真正开始工作。USB Host通过设备请求命令来获取或者设置USB Device的参数/数据。这些信息是通过存储在设备中的USB 描述符来体现的。 多配置USB设备枚举过程和多字符串描述符的枚举是相同的,大致过程如下:
- 供电;
- 总线复位;
- 获取设备描述符;
- 总线复位;
- 设置地址;
- 获取设备描述符;
- 获取配置描述符1;
- 获取配置描述符2;
- …
- 获取字符串描述符1;
- 获取字符串描述符2;
- …
- 设置配置;
- …
该部分主要针对 USB2.0 规范的第九章。USB设备连接到HOST时,HOST必须通过默认的控制管道对其进行枚举,完成获得其设备描述、进行地址分配、获得其配置描述、进行配置等操作后方可正常使用。USB设备的即插即用特性即依赖于此。
USB设备的6种状态:连接状态、上电状态、默认状态、地址状态、配置状态、挂起状态,六者之间的关系图如下所示:
连接(Attached)
设备可以连接到USB或者从USB上拔出。USB设备从总线上拨出后的状态在规范没定义,只说明一旦USB连到总线要求的操作以及属性。
上电(Powered)
设备可以支持自供电和总线供电配置。 某些设备配置支持任意电源。 仅当设备是自供电时,其他设备配置才可用。 设备通过配置描述符报告其电源功能。 当前电源被报告为设备状态的一部分。 设备可以在任何时间改变其电源,例如从自供电到总线供电。 如果配置能够支持两种功耗模式,则为该配置报告的功率最大值是设备在任一模式下从VBUS中获取的最大值。 无论模式如何,设备都必须遵守此最大值。 如果配置仅支持一种电源模式且设备的电源发生变化,则设备将丢失其当前配置和地址并返回到Powered状态。 如果设备是自供电的并且其当前配置需要超过100 mA,那么如果设备切换为总线供电,则必须返回到地址状态。 如果本地电源丢失,则允许使用VBUS为集线器控制器供电的自供电集线器保持在已配置状态。 有关详细信息,请参阅第11.13节。
USB设备的电源可来自外部电源,也可从USB接口的集线器而来。电源来自外部电源的USB设备被称作自给电源式的(self-powered)。尽管自给电源式的USB设备可能在连接上USB接口以前可能已经带电,但它们直到连线上USB接口后才能被看作是加电状态(Powered state)。而这时候VBUS已经对设备产生作用了。
一个设备可能有既支持自给电源的,同时也支持总线电源式的配置。有一些支持其中的一种,而另一些设备配置可能只有在自给电源下才能被使用。设备对电源支持的能力是通过配置描述表(configuration descriptor)来反映的。当前的电源供给形式被作为设备状态的一部分被反映出来。设备可在任何时候改变它们的供电来源,比如说:从自给式向总线式改变,如果一个配置同时支持两种模式,那此状态的最大电源需求就是指设备在两种模式下从VBUS上获取电能的最大值。设备必须以此最大电源作为参照,而究竟处于何状态是不考虑的。如果有一配置仅支持一种电源模式,那么电源模式的改变会使得设备失去当前配置与地址,返回加电状态。如果一个设备是自给电源式,并且当前配置需要大于100mA电流,那么如果此设备转到了总线电源式,它必须返回地址状态(Address state)。自给电源式集线器使用VBUS来为集线控制器(Hub controller)提供电源,因而可以仍然保持配置状态(Configured state),尽管自给电源停止提供电源。
默认状态(Default)
设备上电后,它不响应任何总线处理,直到总线接收到复位信号为止.接收到复位信号后,用默认的地址可以对设备寻址.
当用复位过程完成后,USB设备在正确的速度下操作(即低速/全速/高速).低速和全速的数据选择由设备的终端电阻决定.能进行高速操作的设备决定它是否在复位的过程的一部分执行高速操作.
能进行高速操作的设备在全速的电气环境中操作时,必须能以全速成功复位.设备成功复位后,设备必须成功响应设备和配置描述符请求,并且返回适当的信息.当在全速下工作时,设备可能或者不能支持预定义的功能.
地址(Address)
所有的USB设备在加电复位以后都使用缺省地址。每一设备在连接或复位后由主机分配一个唯一的地址。当USB设备处于挂起状态时,它保持这个地址不变。
USB设备只对缺省通道(Pipe)请求发生响应,而不管设备是否已经被分配地址或在使用缺省地址。
配置状态( Configured )
在USB设备正常工作以前,设备必须被正确配置。从设备的角度来看,配置包括一个将非零值写入设备配置寄存器的操作。配置一个设备或改变一个可变的设备设置会使得与这个相关接口的终端结点的所有的状态与配置值被设成缺省值。这包括将正在使用(date toggle)的结点(end point)的 (Date toggle)被设置成DATA0。
挂起状态(Suspended)
为节省电源,USB设备在探测不到总线传输时自动进入中止状态。当中止时,USB设备保持本身的内部状态,包括它的地址及配置。
所有的设备在一段特定的时间内探测不到总线活动时必须进入中止态。不管设备是被分配了非缺省的地址或者是被配置了,已经连接的设备必须在任何加电的时刻随时准备中止。总线活动的中止可能是因为主机本身进入了中止状态。另外,USB设备必须在所连接的集线器端口失效时进入中止态。这就是所指的选择性中止(Selective suspend)。
USB设备在总线活动来到时结束中止态。USB设备也可以远程唤醒的电流信号来请求主机退出中止态或选择性中止态。具体设备具有的远程唤醒的能力是可选的,也就是说,如果一个设备有远程唤醒的能力,此设备必须能让主机控制此能力的有效与否。当设备复位时,远程唤醒能力必须被禁止。
总线枚举(Bus Enumeration)
以下部分摘录自网友Arrow的文章 USB枚举过程,感谢作者。更详细的信息请去作者博客查看!
用户把USB设备插入USB端口或给系统启动时设备上电
这里指的USB端口指的是主机下的根hub或主机下行端口上的hub端口。Hub给端口供电,连接着的设备处于上电状态。此时,USB设备处于加电状态,它所连接的端口是无效的。
Hub监测它各个端口数据线上(D+/D-)的电压
在hub端,数据线D+和D-都有一个阻值在14.25k到24.8k的下拉电阻Rpd,而在设备端,D+(全速,高速)和D-(低速)上有一个1.5k的上拉电阻Rpu。当设备插入到hub端口时,有上拉电阻的一根数据线被拉高到幅值的90%的电压(大致是3V)。hub检测到它的一根数据线是高电平,就认为是有设备插入,并能根据是D+还是D-被拉高来判断到底是什么设备(全速/低速)插入端口(全速、高速设备的区分在我将来的文章中描述)。如下图。
检测到设备后,hub继续给设备供电,但并不急于与设备进行USB传输。
Host了解连接的设备
每个hub利用它自己的中断端点向主机报告它的各个端口的状态(对于这个过程,设备是看不到的,也不必关心),报告的内容只是hub端口的设备连接/断开的事件。如果有连接/断开事件发生,那么host会发送一个 Get_Port_Status请求(request)给hub以了解此次状态改变的确切含义。Get_Port_Status等请求属于所有hub都要求支持的hub类标准请求(standard hub-class requests)。
Hub检测所插入的设备是高速还是低速设备
hub通过检测USB总线空闲(Idle)时差分线的高低电压来判断所连接设备的速度类型,当host发来Get_Port_Status请求时,hub就可以将此设备的速度类型信息回复给host。USB 2.0规范要求速度检测要先于复位(Reset)操作。
hub复位设备
主机一旦得知新设备已连上以后,它至少等待100ms以使得插入操作的完成以及设备电源稳定工作。然后主机控制器就向hub发出一个 Set_Port_Feature请求让hub复位其管理的端口(刚才设备插上的端口)。hub通过驱动数据线到复位状态(D+和D-全为低电平 ),并持续至少10ms。当然,hub不会把这样的复位信号发送给其他已有设备连接的端口,所以其他连在该hub上的设备自然看不到复位信号,不受影响。
Host检测所连接的全速设备是否是支持高速模式
因为根据USB 2.0协议,高速(High Speed)设备在初始时是默认全速(Full Speed )状态运行,所以对于一个支持USB 2.0的高速hub,当它发现它的端口连接的是一个全速设备时,会进行高速检测,看看目前这个设备是否还支持高速传输,如果是,那就切到高速信号模式,否则就一直在全速状态下工作。
同样的,从设备的角度来看,如果是一个高速设备,在刚连接bub或上电时只能用全速信号模式运行(根据USB 2.0协议,高速设备必须向下兼容USB 1.1的全速模式)。随后hub会进行高速检测,之后这个设备才会切换到高速模式下工作。假如所连接的hub不支持USB 2.0,即不是高速hub,不能进行高速检测,设备将一直以全速工作。
Hub建立设备和主机之间的信息通道
主机不停地向hub发送Get_Port_Status请求,以查询设备是否复位成功。Hub返回的报告信息中有专门的一位用来标志设备的复位状态。
当hub撤销了复位信号,设备就处于默认/空闲状态(Default state),准备接收主机发来的请求。设备和主机之间的通信通过控制传输,默认地址0,端点号0进行。此时,设备能从总线上得到的最大电流是100mA。(所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。)
主机发送Get_Descriptor请求获取默认管道的最大包长度
默认管道(Default Pipe)在设备一端来看就是端点0。主机此时发送的请求是默认地址0,端点0,虽然所有未分配地址的设备都是通过地址0来获取主机发来的请求,但由于枚举过程不是多个设备并行处理,而是一次枚举一个设备的方式进行,所以不会发生多个设备同时响应主机发来的请求。
设备描述符的第8字节代表设备端点0的最大包大小。虽然说设备所返回的设备描述符(Device Descriptor)长度只有18字节,但系统也不在乎,此时,描述符的长度信息对它来说是最重要的,其他的瞄一眼就过了。当完成第一次的控制传输后,也就是完成控制传输的状态阶段,系统会要求hub对设备进行再一次的复位操作(USB规范里面可没这要求)。再次复位的目的是使设备进入一个确定的状态。
主机给设备分配一个地址
主机控制器通过Set_Address请求向设备分配一个唯一的地址。在完成这次传输之后,设备进入地址状态(Address state),之后就启用新地址继续与主机通信。这个地址对于设备来说是终生制的,设备在,地址在;设备消失(被拔出,复位,系统重启),地址被收回。同一个设备当再次被枚举后得到的地址不一定是上次那个了。
主机获取设备的信息
主机发送 Get_Descriptor请求到新地址读取设备描述符,这次主机发送Get_Descriptor请求可算是诚心,它会认真解析设备描述符的内容。设备描述符内信息包括端点0的最大包长度,设备所支持的配置(Configuration)个数,设备类型,VID(Vendor ID,由USB-IF分配), PID(Product ID,由厂商自己定制)等信息。Get_Descriptor请求(Device type)和设备描述符(已抹去VID,PID等信息)见下图:
标准Get_Descriptor请求
之后主机发送Get_Descriptor请求,读取配置描述符(Configuration Descriptor),字符串等,逐一了解设备更详细的信息。事实上,对于配置描述符的标准请求中,有时wLength一项会大于实际配置描述符的长度(9字节),比如255。这样的效果便是:主机发送了一个Get_Descriptor_Configuration 的请求,设备会把接口描述符,端点描述符等后续描述符一并回给主机,主机则根据描述符头部的标志判断送上来的具体是何种描述符。
接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。
如果有字符串描述符的话,还要获取字符串描述符。另外HID设备还有HID描述符等。
主机给设备挂载驱动(复合设备除外)
主机通过解析描述符后对设备有了足够的了解,会选择一个最合适的驱动给设备。 然后tell the world(announce_device)说明设备已经找到了,最后调用设备模型提供的接口device_add将设备添加到 usb 总线的设备列表里,然后 usb总线会遍历驱动列表里的每个驱动,调用自己的 match(usb_device_match) 函数看它们和你的设备或接口是否匹配,匹配的话调用device_bind_driver函数,现在就将控制权交到设备驱动了。
对于复合设备,通常应该是不同的接口(Interface)配置给不同的驱动,因此,需要等到当设备被配置并把接口使能后才可以把驱动挂载上去。
实际情况没有上述关系复杂。一般来说,一个设备就一个配置,一个接口,如果设备是多功能符合设备,则有多个接口。端点一般都有好几个,比如Mass Storage设备一般就有两个端点(控制端点0除外)。
设备驱动选择一个配置
驱动(注意,这里是驱动,之后的事情都是有驱动来接管负责与设备的通信)根据前面设备回复的信息,发送Set_Configuration请求来正式确定选择设备的哪个配置(Configuration)作为工作配置(对于大多数设备来说,一般只有一个配置被定义)。至此,设备处于配置状态(Configured),当然,设备也应该使能它的各个接口(Interface)。
对于复合设备,主机会在这个时候根据设备接口信息,给它们挂载驱动。
设备请求
所有USB设备都会响应设备默认控制管道上来自主机的请求。 这些请求使用控制转移进行。 请求和请求的参数在Setup数据包中发送到设备。 主机负责建立下表中列出的字段值。 每个SETUP包都有八个字节。
- bmRequestType: 该位图字段标识特定请求的特征。 特别是,该字段标识控制传输第二阶段中的数据传输方向。 如果wLength字段为零,则表示方向位的状态将被忽略,表示没有数据阶段。
USB规范定义了所有设备必须支持的一系列标准请求。 这些在下一节的表中列举。 另外,设备类可以定义额外的请求。 设备供应商也可以定义设备支持的请求。
可以将请求指向设备,设备上的接口或设备上的特定端点。 该字段还指定了请求的预期收件人。 当指定接口或端点时,wIndex字段
标识接口或端点。 - bRequest: 该字段指定了特定的请求。
bmRequestType字段
中的Type位
修改此字段的含义。 本规范仅在位重置为零时指定bRequest字段的值,表示标准请求见下一节的表格。 - wValue: 该字段的内容根据要求而有所不同。 它用于将参数传递给设备,特定于请求。具体见后文的说明。
- wIndex: 该字段的内容根据要求而有所不同。 它用于将参数传递给设备,特定于请求。
wIndex字段
通常用于指定端点或接口的请求中。 下图显示了用于指定端点时的格式。
方向位设置为零,以指示具有指定端点号的OUT端点以及指示IN端点。 对于控制管道,请求应该将方向位设置为零,但器件可以接受方向位的任一值。
下图显示了wIndex用于指定接口时的格式。
- wLength: 该字段指定在控制转移的第二阶段期间传输的数据的长度。 数据传输的方向(主机到设备或设备到主机)由
bmRequestType字段
的Direction位
指示。 如果该字段为零,则不存在数据传输阶段。
在输入请求中,设备不得返回比wLength
值指示的更多数据; 它可能会返回更少。 在输出请求中,wLength
将始终指示主机要发送的确切数据量。 如果主机发送的数据多于wLength
中指定的数据,则设备行为未定义。
标准设备请求
本节介绍为所有USB设备定义的标准设备请求。 表9-3给出了标准设备请求,而表9-4和表9-5分别给出了标准请求代码和描述符类型。
USB设备必须响应标准的设备请求,即使设备尚未分配地址或尚未配置。
Feature selectors 用于启用或设置特定功能,如设备,接口或端点特有的远程唤醒功能。 表9-6给出了功能选择器的值。
如果对USB设备发出不支持或无效的请求,则设备通过在请求的数据或状态阶段返回STALL做出响应。 如果设备在设置阶段检测到错误,则最好在数据或状态阶段的较早阶段返回STALL。 收到不受支持或无效的请求不会导致设置控制管道上的可选Halt功能。 如果出于任何原因,设备由于错误情况而无法通过其默认控制管道进行通信,则必须重置设备以清除状况并重新启动默认控制管道。
Clear Feature
此请求用于清除或禁用特定功能。
wValue
中的功能选择器值必须适合接收者。 当接收者是设备时,只有设备功能选择器值可以使用;当接收者是接口时,只有接口功能选择器值可以使用;并且当接收者是端点时可以使用端点功能选择器值。
不存在或引用不存在的接口或端点的功能的ClearFeature()
请求将导致设备响应请求错误。
如果wLength
不为零,则未指定设备行为!
- Default state: 当设备处于默认状态时收到该请求,则设备行为是未指定的。
- Address state: 当设备处于地址状态时,此请求有效; 对接口或端点零以外的端点的引用会造成设备响应请求错误。
- Configured state: 当设备处于Configured状态时,此请求有效。
Test_Mode特性不能被该操作清楚
Get Configuration
该请求返回当前设备配置值。
如果返回值为零,则说明设备未配置。如果wValue
,wIndex
或wLength
不符合上述规定,则未指定设备行为。
- Default state: 当设备处于默认状态时收到该请求,则设备行为是未指定的。
- Address state: 必须返回0.
- Configured state: 必须返回当前配置的非零值
bConfigurationValue
。
Get Descriptor
如果描述符存在,该请求将返回指定的描述符。
wValue字段
(2个字节)的高字节中为描述符类型(参见表9-5),低字节指定描述符索引。描述符索引用于在设备中实现多个相同类型的描述符时选择特定描述符(描述符索引仅用于配置描述符和字符串描述符)。 例如,一个设备可以实现多个配置描述符。而对于可以通过GetDescriptor()
请求检索其他的标准描述符(例如设备描述符),描述符索引必须使用零。 用于描述符索引的值的范围从0到比设备实现的那种描述符的数量少一个。wIndex字段
(2字节)指定字符串描述符的语言ID,当不是字符串描述符时,则该值为零。wLength字段
(2个字节)指定要返回的字节数。 如果描述符长于wLength字段,则只返回描述符的初始字节。 如果描述符比wLength字段
短,则当请求进一步的数据时,设备通过发送短分组来指示控制传输的结束。 短数据包定义为比最大有效负载大小或长度为零的数据包短的数据包(具体请参阅规范的第5章)。- 举例:获取设备描述符报文如下(注意字节顺序(USB规定低字节在前)):
80 06 00 01 00 00 12 00
该请求只用于请求以下三种类型的描述符:设备描述符(包括设备限定符device_qualifier) 、配置描述符(包括other_speed_configuration) 、字符串描述符。对配置描述符的请求返回单个请求中所有接口的配置描述符,所有接口描述符和端点描述符。第一个接口描述符在配置描述符之后。第一个接口的端点描述符紧随第一个接口描述符。如果有其他接口,它们的接口描述符和端点描述符将紧随第一个接口的端点描述符。
所有设备都必须提供设备描述符和至少一个配置描述符。 如果一个设备不支持请求的描述符,它会回应一个请求错误。
- Default state: 此时该请求是有效的。
- Address state: 此时该请求是有效的。
- Configured state: 此时该请求是有效的。
Get Interface
该请求返回指定接口的选定备用设置。
某些USB设备的配置具有互斥设置的接口。 该请求允许主机确定当前选择的备用设置。
如果wValue
或wLength
不符合上述规定,则设备行为未指定。如果指定的接口不存在,那么设备将响应请求错误。
- Default state: 当设备处于默认状态时收到该请求,则设备行为是未指定的。
- Address state: 设备给出请求错误响应
- Configured state: 请求是有效的。
Get Status
此请求返回指定接收者的状态。
bmRequestType字段
的Recipient bits
指定了所需的接收者。 返回的数据是指定接收者的当前状态。
如果wValue
或wLength
不符合上面的规定,或者如果wIndex
对于设备状态请求非零,则未指定设备的行为。如果指定的接口或端点不存在,那么设备将响应请求错误。
- Default state: 当设备处于默认状态时收到该请求,则设备行为是未指定的。
- Address state: 如果指定了端点0以外的端点或者是接口,则设备会响应请求错误。
- Configured state: 如果指定的端点或者接口不存在,设备会响应请求错误。
GetStatus()
对设备的请求的返回结果格式如下:
Self Powered
字段指示设备当前是否自供电。 如果D0重置为零,则该设备由总线供电。 如果D0设置为1,则设备是自供电的。 SelfFeature
字段可能不会被SetFeature()
或ClearFeature()
请求更改。
Remote Wakeup
字段指示设备当前是否被允许请求远程唤醒。 支持远程唤醒的设备的默认模式被禁用。 如果D1被重置为零,则设备发信号通知远程唤醒的能力被禁用。 如果D1设置为1,则启用设备发送远程唤醒信号的能力。 远程唤醒字段可以通过使用DEVICE_REMOTE_WAKEUP
功能选择器的SetFeature()
和ClearFeature()
请求来修改。
GetStatus()
对接口的请求的返回结果格式如下:
GetStatus()
对端点的请求的返回结果格式如下:
需要为所有中断和批量端点类型实施暂停功能。 如果端点当前暂停,则暂停功能设置为1。 否则,暂停功能重置为零。 可以选择使用SetFeature(ENDPOINT_HALT)
请求来设置暂停功能。
Set Address
wValue
字段指定用于所有后续访问的设备地址。
如之前所述,请求实际上可能会导致最多三个阶段。 在第一阶段,设置数据包被发送到设备。 在可选的第二阶段,数据在主机和设备之间传输。 在最后阶段,状态在主机和设备之间传输。 数据和状态传输的方向取决于主机是向设备发送数据还是设备正在向主机发送数据。 状态阶段转移始终与数据阶段相反。 如果没有数据阶段,则状态阶段从设备到主机。
最初的SETUP数据包之后的阶段采用与安装数据包相同的设备地址。 直到此请求的状态阶段成功完成后,USB设备才会更改其设备地址。 请注意,这是此请求和所有其他请求之间的区别。 对于所有其他请求,指示的操作必须在状态阶段之前完成。
如果指定的设备地址大于127,或者wIndex或wLength非零,则未指定设备的行为。
- Default state: 如果指定的地址非零,则设备应进入地址状态; 否则,设备保持默认状态(这不是错误状态)。
- Address state: 如果指定的地址为零,则设备将进入默认状态; 否则,设备保持在地址状态,但使用新指定的地址。
- Configured state: 设备处于Configured状态时收到此请求时的设备行为是未指定的。
Set Configuration
wValue
字段的低字节指定了所需的配置。 该配置值必须为零或匹配配置描述符中的配置值。 如果配置值为零,则设备处于其地址状态。 wValue
字段的高字节保留。
如果wIndex
,wLength
或wValue
的高字节不为零,则此请求的行为未指定。
- Default state: 在设备处于默认状态时收到此请求时的设备行为未指定。
- Address state: 如果指定的配置值为零,则设备保持在地址状态。 如果指定的配置值与配置描述符中的配置值相匹配,则选择该配置并且设备进入配置状态。 否则,设备会响应请求错误。
- Configured state: 如果指定的配置值为零,则设备进入地址状态。 如果指定的配置值与配置描述符中的配置值相匹配,则选择该配置并且设备保持配置状态。 否则,设备会响应请求错误。
Set Descriptor
该请求是可选的,可用于更新现有的描述符或添加新的描述符。
wValue
字段的高字节为描述符类型(参见表9-5)和低字节为描述符索引。 描述符索引用于在设备中实现多个相同类型的描述符时选择特定的描述符(仅用于配置和字符串描述符)。 例如,一个设备可以实现多个配置描述符。 对于可以通过SetDescriptor()
请求设置的其他标准描述符,必须使用零描述符索引。 用于描述符索引的值的范围从0到比设备实现的那种描述符的数量少一个。
wIndex
字段指定字符串描述符的语言ID,或者为其他描述符重置为零。 wLength字段指定要从主机传输到设备的字节数。
描述符类型唯一允许的值是设备,配置和字符串描述符类型。
如果此请求不受支持,则设备将响应请求错误。
- Default state: 在设备处于默认状态时收到此请求时的设备行为未指定。
- Address state: 如果支持,当设备处于地址状态时,这是一个有效的请求。
- Configured state: 如果支持,当设备处于Configured状态时,这是一个有效的请求。
Set Feature
wValue
中的功能选择器值必须适合收件人。 当收件人是设备时,只能使用设备功能选择器值; 当接收者是接口时,只有接口特征选择器值可以被使用,并且当接收者是端点时,可以仅使用端点特征选择器值。
引用无法设置或不存在的功能的SetFeature()请求会导致在请求的状态阶段返回STALL。
如果wLength
非零,那么设备的行为没有被指定。
如果指定了不存在的端点或接口,则设备会响应请求错误。
- Default state: 处于默认状态时,设备必须能够接受SetFeature(TEST_MODE,TEST_SELECTOR)请求。 未指定设备处于默认状态时其他SetFeature请求的设备行为。
- Address state: 如果指定了端点0以外的接口或端点,则设备会响应请求错误。
- Configured state: 这是一个有效的请求。
Set Interface
该请求允许主机为指定的接口选择备用设置。
某些USB设备的配置具有互斥设置的接口。 此请求允许主机选择所需的备用设置。 如果设备仅支持指定接口的默认设置,则可能会在请求的状态阶段返回STALL。 此请求不能用于更改已配置接口集(必须使用SetConfiguration()请求)。
如果接口或备用设置不存在,则设备将响应请求错误。 如果wLength非零,那么设备的行为没有被指定。
- Default state: 在设备处于默认状态时收到此请求时的设备行为未指定。
- Address state: 必须返回请求错误。
- Configured state: 这是一个有效的请求。
Synch Frame
略
描述符(Descriptor )
本部分主要针对USB规范的第9.5节和第9.6节。这种USB 描述符也可以看作是USB 设备的身份证明。设备描述符的分类见上表9-6。USB规范中定义了以下几种描述符:***Device(设备)、Device_Qualifier(设备限定)、Configuration(配置)、Other_Speed_Configuration(其他速度配置)、Interface(接口)、Endpoint(端点)、String(字符串)***。部分描述符间的关系如下图所示:
一个设备有且只能有一个设备描述符,之后的描述符都允许有多个不同的描述符。
USB设备使用描述符报告其属性。 描述符是具有定义格式的数据结构。 每个描述符以一个字节宽的字段开始,该字段包含描述符中总字节数,后跟一个标识描述符类型的字节宽字段。
在USB主机访问USB设备的描述符时,USB设备依照设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符顺序将所有描述符传给主机。一设备至少要包含设备描述符、配置描述符和接口描述符,如果USB设备没有端点描述符,则它仅仅用默认管道与主机进行数据传输。
关于描述符字段的说明
首位小写字母 意义 b 1 字节Byte w 16 位的2 字节二进制(Word ) bm 位图(Bit Map ) bcd BCD 码 i 索引( Index) id 标识( Identifier )
USB规范预先定义了的各种标准USB描述符,规范中定义的标准描述符只能通过修订通用串行总线规范进行修改或扩展。具体如下:
设备(Device)
设备描述符描述有关USB设备的一般信息。 它包含全局适用于设备和所有设备配置的信息。USB设备只有一个设备描述符。
具有全速和高速不同设备信息的高速设备也必须具有device_qualifier描述符。
所有USB设备都有一个默认控制管道。 设备描述符中描述了设备默认控制管道的最大数据包大小。 配置描述符中描述了特定于配置及其接口的端点。 配置及其接口不包含默认控制管道的端点描述符。 除了最大数据包大小之外,默认控制管道的特性由该规范定义,并且对于所有USB设备都是相同的。
- 每一个设备有且只有一个设备描述符
- 默认控制管道的数据包的长度( 端点0长度)是在设备描述符中定义, 而不像其他端点在端点描述符中定义。
- 共14 个字段,长18 Byte
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | 0x12 | 设备描述符的字节数大小 |
1 | bDescriptorType | 1 | 0x01 | 设备描述符类型编号。具体见上文的表 9 - 5 |
2 | bcdUSB | 2 | 0xJJMN | USB版本号。格式为:JJ.M.N(JJ-主要版本号,M-次要版本号,N-次次要版本号)定义的bcdUSB字段的值为0xJJMN,例如版本2.1.3以值0x0213表示,版本2.0用值0x0200表示。 |
4 | bDeviceClass | 1 | 类 | Class代码(由USB-IF分配)。如果该字段重置为零,则配置中的每个接口指定其自己的类信息,并且各个接口独立运行。如果此字段设置为1到FEH之间的值,则设备支持不同接口上的不同类规范,并且接口可能无法独立运行。 该值标识用于聚合接口的类定义。如果为FFH表示厂商自定义 |
5 | bDeviceSubClass | 1 | 子类 | Subclass代码(由USB-IF分配)。受bDeviceClass 字段的值限定。如果bDeviceClass 为 0,这此值必须为 0。如果bDeviceClass 字段未设置为FFH,则所有值都保留给USB-IF分配。 |
6 | bDeviceProtocol | 1 | 协议 | 协议代码(由USB-IF分配)。 |
7 | bMaxPacketSize0 | 1 | 控制传输端点0包大小 | 端点0最大包大小,只能是8、16、32或64。如果设备以高速运行,则必须为64,表示最多64字节的数据包。 高速操作不允许控制端点(端点0)其他最大数据包大小。 |
8 | idVendor | 2 | ID编号 | 厂商编号(由USB-IF分配) |
10 | idProduct | 2 | ID编号 | 产品编号(由USB-IF分配) |
12 | bcdDevice | 2 | BCD码 | 以二进制编码的十进制表示的设备出厂编号 |
14 | iManufacturer | 1 | 索引 | 描述厂商字符串索引。当值为0时,表示没有厂商字符串,当为其他值时,主机会利用这个索引值来获取相应的字符串。 |
15 | iProduct | 1 | 索引 | 描述产品字符串的索引。当值为0时,表示没有产品字符串,当为其他值时,主机会利用这个索引值来获取相应的字符串。 |
16 | iSerialNumber | 1 | 索引 | 描述设备序列号字符串的索引。当值为0时,表示没有序列号字符串,当为其他值时,主机会利用这个索引值来获取相应的字符串。 |
17 | bNumConfigurations | 1 | 配置描述符个数 | bNumConfigurations字段标识设备支持的配置数量。仅表示当前运行速度下的配置数量。计数中不包括其他运行速度的配置。 如果特定速度的设备有特定配置,则bNumConfigurations 字段仅反映单个速度的配置数量,而不是两个速度的配置总数量。 |
设备类代码bDeviceClass可在USB官网http://www.usb.org/developers/defined_class查询到,该页面中有非常详细的类及子类的详细信息。如下图
注意:上表列出来的类定义为 设备描述符bDeviceClass字段和接口描述符bInterfaceClass字段这两个的,表中的Descriptor Usage 表示了 类用在哪个描述符中!
设备限定(Device_Qualifier)
device_qualifier描述符描述有关高速设备的信息,如果设备以另一种速度运行,该信息将会改变。 例如,如果设备当前正在全速运行,则device_qualifier会返回有关如何以高速运行的信息,反之亦然。 下表9-9显示了device_qualifier描述符的字段。
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | Number | 本描述符的长度 |
1 | bDescriptorType | 1 | Constant | 描述符类型,见上文表9-5 |
2 | bcdUSB | 2 | BCD | USB规范版本号 (e.g.,0200H for V2.00 ) |
4 | bDeviceClass | 1 | Class | 类代码 |
5 | bDeviceSubClass | 1 | SubClass | 子类代码 |
6 | bDeviceProtocol | 1 | Protocol | 规约代号 |
7 | bMaxPacketSize0 | 1 | Number | 其他速度下的包大小 |
8 | bNumConfigurations | 1 | Number | 其他速度的配置 |
9 | bReserved | 1 | Zero | 为以后保留,必须为0 |
如果仅全速设备(设备描述符版本号等于0200H)接收到device_qualifier的GetDescriptor()请求,则它必须响应请求错误。 除非首先成功检索device_qualifier描述符,否则主机不得对other_speed_configuration描述符发出请求。
配置(Configuration)
配置描述符描述了关于特定设备配置的信息。 描述符包含一个bConfigurationValue字段,该字段的值用作SetConfiguration()请求的参数时,会使设备采用所描述的配置。
描述符描述配置提供的接口数量。 每个接口可以独立运行。 例如,ISDN设备可能配置有两个接口,每个接口提供64 Kb / s的双向信道,在主机上有单独的数据源或接收器。 另一种配置可能将ISDN设备呈现为单个接口,将两个通道绑定为一个128 Kb / s的双向通道。
配置完成后,设备可能会对配置进行有限的调整。 如果某个特定接口具有备用设置,则可以在配置后选择备用设备。 表9-10显示了标准配置描述符。
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | 0x09 | 配置描述符的字节数大小 |
1 | bDescriptorType | 1 | 0x02 | 配置描述符类型编号,见上文的表 9 - 5 |
2 | wTotalLength | 2 | 数字 | 这是一个以2字节二进制数为内容的字段。该字段表示该配置所返回的所有描述符( 包括配置、接口和端点描述符) 的大小总和。 |
4 | bNumInterfaces | 1 | 接口描述符个数 | 此配置所支持的接口数量 |
5 | bConfigurationValue | 1 | 数字 | SetConfiguration命令需要的参数值 |
6 | iConfiguration | 1 | 索引 | 描述该配置的字符串的索引值 |
7 | bmAttributes | 1 | 位图 | 配置特征。供电模式的选择, D7保留固定为1; D6值为1表示自供电,值为0表示总线供电; D5值为1表示支持远程唤醒,值为0则不支持; D4~D0没有意义固定为0 |
8 | MaxPower | 1 | 字段值*2(mA) | 设备从总线提取的最大电流(<=500mA) |
其他速度配置(Other_Speed_Configuration)
表9-11中显示的other_speed_configuration描述符描述了高速设备的配置,如果它正在以其他可能的速度运行。 other_speed_configuration的结构与配置描述符相同。
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | Number | 本描述符的长度 |
1 | bDescriptorType | 1 | Constant | 描述符类型 |
2 | wTotalLength | 2 | Number | 要求返回的数据的总长度 |
4 | bNumInterfaces | 1 | Number | 本速度下支持的接口的数量 |
5 | bConfigurationValue | 1 | Number | 用于选择配置的值 |
6 | iConfiguration | 1 | Index | 字符串描述符的索引 |
7 | bmAttributes | 1 | Bitmap | 与配置描述符相同 |
8 | bMaxPower | 1 | mA | 与配置描述符相同 |
接口(Interface)
接口描述符描述配置中的特定接口。 一个配置提供一个或多个接口,每个接口具有零个或多个端点描述符,用于描述配置中的一组唯一端点。 当配置支持多个接口时,特定接口的端点描述符将遵循GetConfiguration()请求返回的数据中的接口描述符。 接口描述符总是作为配置描述符的一部分返回。 接口描述符不能通过GetDescriptor()或SetDescriptor()请求直接访问。
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | Number | 接口描述符的字节数大小 |
1 | bDescriptorType | 1 | Constant | 本描述符类型 |
2 | bInterfaceNumber | 1 | Number | 接口编号。基于零的值标识此配置支持的并发接口阵列中的索引。如果一个配置拥有N个接口, 那么这些接口都是互不相干的, 每一个接口都有惟一的编号, USB 就是通过此字段来识别不同的接口。默认值为0。 |
3 | bAlternateSetting | 1 | Number | USB设备配置与USB配置描述符是一一对应的, 即一个配置只能有一个配置描述符。虽然由bInterfaceNumber字段可知, 每一个接口都有一个惟一确定的接口编号, 但是一个接口却可以由不只一个接口描述符来描述它。USB 允许多个接口描述符来描述同一个接口, 且这些描述符都可通过命令切换。此字段就是每一个这类描述符惟一的编号。USB可通过调用这个字段来切换描述同一个接口的不同描述符。控制传输中的Get_Inter face 命令可以用来得到目前正在使用的描述一个确定接口的接口描述符的编号, 即此字段。而Set_Inte rface 命令则以此字段值为参数, 用来使相应的接口描述符描述某个确定的接口 |
4 | bNumEndpoints | 1 | Number | 此接口使用的端点数(不包括端点零)。 如果此值为零,则此接口仅使用默认控制管道。 |
5 | bInterfaceClass | 1 | Class | 类号 (由USB-IF分配). 零值保留用于未来的标准化。 如果此字段设置为FFH,则接口类是供应商特定的。 所有其他值都保留给USB-IF分配。 |
6 | bInterfaceSubClass | 1 | SubClass | 子类号 (由USB-IF分配). 这些代码由bInterfaceClass 字段的值限定。 如果bInterfaceClass 字段重置为零,则该字段也必须重置为零。 如果bInterfaceClass 字段未设置为FFH,则所有值都保留给USB-IF分配。 |
7 | bInterfaceProtocol | 1 | Protocol | 规约号 (assigned by the USB). 这些代码由bInterfaceClass 和bInterfaceSubClass 字段的值限定。 如果接口支持特定于类的请求,则该代码将识别设备使用的协议,如设备类的规范所定义。 如果此字段重置为零,则设备不在此接口上使用类特定的协议。 如果此字段设置为FFH,则该设备使用此接口的供应商特定协议。 |
8 | iInterface | 1 | Index | 描述此接口的字符串描述符的索引 |
bInterfaceClass
字段将设备描述符章节的表格。或者直接去USB官网http://www.usb.org/developers/defined_class查询。
端点(Endpoint)
用于接口的每个端点都有自己的描述符。 该描述符包含主机为确定每个端点的带宽需求所需的信息。 一个端点描述符总是作为GetDescriptor(配置)请求返回的配置信息的一部分返回。 端点描述符不能通过GetDescriptor()或SetDescriptor()请求直接访问。 从不会有端点零的端点描述符。 表9-13显示了标准的端点描述符。
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | Number | 本描述符字节大小 |
1 | bDescriptorType | 1 | Constant | 本描述符类型 |
2 | bEndpointAddress | 1 | endpoint | USB设备上端点的地址。 地址编码如下: Bit 3…0:端点号 Bit 6…4:保留,赋值为零 Bit 7: 方向, 控制端点忽略。0 = OUT endpoint;1 = IN endpoint |
3 | bmAttributes | 1 | Bitmap | 该字段描述使用bConfigurationValue 配置端点的属性。Bits 1…0: Transfer Type 00 = Control 01 = Isochronous 10 = Bulk 11 = Interrupt 如果不是同步端点,则位5…2被保留并且必须设置为零。 如果是同步的,则它们被定义如下: Bits 3…2: Synchronization Type 00 = No Synchronization 01 = Asynchronous 10 = Adaptive 11 = Synchronous Bits 5…4: Usage Type 00 = Data endpoint 01 = Feedback endpoint 10 = Implicit feedback Data endpoint 11 = Reserved 所有其他位都保留,必须重置为零。主机必须忽略保留位。 |
4 | wMaxPacketSize | 2 | Number | 选择此配置时,此端点能够发送或接收的最大数据包大小。 对于同步端点,该值用于保留调度中的总线时间,这是每个(微)帧数据有效负载所需的。管道可能持续使用的带宽实际上比预留的带宽要少。 如有必要,设备会通过其通常的非USB定义机制报告实际带宽。 对于所有端点,第10…0位指定最大数据包大小(以字节为单位)。 对于高速同步和中断端点:位12…11指定每个微帧额外事务机会的数量: 00 = None (1 transaction per microframe) 01 = 1 additional (2 per microframe) 10 = 2 additional (3 per microframe) 11 = Reserved Bits 15…13 are reserved and must be set to zero. |
6 | bInterval | 1 | Number | 轮询数据传输终点的时间间隔。 根据设备运行速度(即1毫秒或125微秒单位)以帧或微帧表示。 对于全速/高速同步端点,此值必须介于1到16之间。bInterval值用作 2 b I n t e r v a l − 1 2^{bInterval-1} 2bInterval−1值的指数; 例如,值为4的间隔表示周期为8( 2 4 − 1 2^{4-1} 24−1)。 对于全/低速中断端点,此字段的值可能为1到255。 对于高速中断端点,bInterval值用作 2 b I n t e r v a l − 1 2^{bInterval-1} 2bInterval−1值的指数; 例如:值为4的间隔表示周期为8( 2 4 − 1 2^{4-1} 24−1)。 值必须为1~16。 对于高速批量/控制OUT端点,bInterval必须指定端点的最大NAK速率。 值为0表示端点从不NAK。 其他值表示每个微针间隔最多一个NAK. 值必须在0~255之间。 |
字符串(String)
字符串描述符是可选的。 如前所述,如果设备不支持字符串描述符,则必须将设备,配置和接口描述符中对字符串描述符的所有引用重置为 0。要不然在枚举过程中,USB主机会尝试去获取字符串描述符,而刚好你又没有,那么枚举就会失败。
- 一般产品是有的字符串描述符的,至少能说明生产厂家、产品信息等等,要不然这个产品多尴尬。。。
- 字符串描述符实际中由:语言ID字符串描述符、厂商代码字符串描述符、产品ID字符串描述符、序列号字符串描述符。其中,语言描述符比较特殊,其索引为0,具体见下文。
字符串描述符使用由UNICODE编码定义的Unicode标准 :The Unicode Standard, Worldwide Character Encoding, Version 3.0, Unicode联盟,Addison-Wesley Publishing Company,Reading,Massachusetts(网址:http://www.unicode.com)。USB设备中的字符串可能支持多种语言。 请求字符串描述符时,请求者使用由USB-IF定义的十六位语言ID(LANGID)指定所需的语言。 目前定义的USB LANGID列表可以在http://www.usb.org/developers/docs.html找到。 所有语言的字符串索引0返回一个字符串描述符,其中包含设备支持的两个字节的LANGID代码数组。 表9-15显示了LANGID代码数组。 USB设备可能会省略所有字符串描述符。 省略所有字符串描述符的USB设备不得返回一个LANGID代码数组。
LANGID代码数组不是以NULL结尾的。 数组大小(以字节为单位)是通过从描述符的第一个字节的值中减去两个来计算的。
Table 9-15. String Descriptor Zero, Specifying Languages Supported by the Device(语言ID字符串描述符)
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | N+2 | 本描述符的字节数大小 |
1 | bDescriptorType | 1 | 描述符类型 | |
2 | wLANGID[0] | 2 | Number | LANGID code zero |
… | … | … | … | … |
N | wLANGID[x] | 2 | Number | LANGID code x |
在枚举过程中,USB主机会向USB设备发送GET_DESCRIPTOR请求,同时wValue字段高字节为描述符类型,字符串描述符的类型为0x03,低字节为字符串描述符索引值,对于语言ID的索引为0,其它字符串描述符索引由设备描述符指定,wIndex字段为语言ID。具体见上文的 Get Descriptor 章节。
UNICODE字符串描述符(如表9-16所示)不以NULL结尾。 字符串长度是通过从描述符的第一个字节的值中减去两个来计算的。除了语言描述符比较特殊外,其他字符串描述符均使用以下结构。
Table 9-16. UNICODE String Descriptor(其他字符串描述符)
偏移量 | 字段名称 | 长度(Byte) | 字段值 | 意义 |
---|---|---|---|---|
0 | bLength | 1 | Number | Size of this descriptor in bytes |
1 | bDescriptorType | 1 | Constant | STRING Descriptor Type |
2 | bString | N | Number | UNICODE encoded string |
在实际使用中,不同类型的字符串描述符。通过GET_DESCRIPTOR中的特殊字节区分,其中语言描述符必须为0,通常各描述符索引如下:
#define USBD_IDX_LANGID_STR 0x00 /* 语言描述符 */
#define USBD_IDX_MFC_STR 0x01 /* 厂商描述符 */
#define USBD_IDX_PRODUCT_STR 0x02 /* 产品描述符 */
#define USBD_IDX_SERIAL_STR 0x03 /* 序列号描述符 */
#define USBD_IDX_CONFIG_STR 0x04 /* 配置描述符 */
#define USBD_IDX_INTERFACE_STR 0x05 /* 接口描述符 */
参考
- Universal Serial Bus Specification Revision 2.0
- 国嵌相关资料
附件
- Bus Hound监听的U盘的报文
- 国嵌资料USB部分