当我们获取到超市的一般信息后,就会想进一步考查其内部的具体情况,通常我们最关注的是货架群的配置。例如,蔬菜水果之类的货架放在超市入口,让顾客敏锐感受到新鲜度从而激发购买欲;冰激凌或速冻食品之类的冷藏货物放在超市出口,顾客就不必担心它们在选购时融化了。主推货品放在展柜右侧,可以抓住人们惯用右手的习惯。当然,这些都只是货架群位置的宏观配置情况,具体的货品摆放也属于配置的一部分。例如,热销的货物摆放在与视线平行的货架层,这可以根据当地居民的普遍身高来定(通常是3、4货架层)。货架底层可以摆放一些体积较大(重)或整箱销售的货物。总之,货架与货品的配置是很有讲究的。
也就是说,我们所说的超市配置不仅仅包含货架,而且也包含货架层与货物。USB设备的配置描述符也是同样的道理,虽然USB规范分别定义了配置、接口、端点描述符,但是从USB总线枚举的过程中可以看到,主机并没有单独获取接口与端点描述符,这是因为它们都从属于配置描述符。 当主机获取配置描述符时,也就意味着会同时获取从属的接口、端点(及其他特定类)描述符 。在清单12.2中,Joystick_ConfigDescriptor数组就代表配置描述符数据,其中包含了与接口和端点描述符相关的数据。
当USB主机从设备中得到了设备描述符后,其会再次发送命令要求设备提交配置描述符。除此配置描述符外,此配置包含的所有接口与端点描述符都将提交给USB主机,但是主机在第一次获得配置描述符后只会读取该配置描述符的前9个字节,这9个字节就是配置描述符信息(暂时还不包含接口与端点描述符的具体信息),相应的结构如表15.1所示。
表15.1 USB配置描述符的结构
配置描述符的第1个字段(bLength)同样代表该描述符的长度,配置描述符固定为9字节,请务必注意: 与设备描述符不一样,该字段不代表Joystick_ConfigDescriptor数组的长度 。因为Joystick_ConfigDescriptor数组还包含了接口与端点(及其他特定类)描述符数据。
第2个字段(bDescriptorType)固定为0x02(见表13.3),表示配置描述符的类型。第3个字段(wTotalLength)表示配置描述符的长度,也就是包含接口、端点(及其他特定类)描述符信息的总长度,它以双字节来表示(而不是BCD码)。清单12.2中Joystick_ConfigDescriptor数组的第3、4个字段分别为JOYSTICK_SIZ_CONFIG_DESC(34)与0x00,所以该配置描述符的总长度为34字节,它也是Joystick_ConfigDescriptor数组的总长度。
第4个字段(bNumInterfaces)表示接口数量,清单12.2中的对应值为1,表示游戏操纵杆设备只有一个接口。如果一个设备包含多个接口,且每个接口代表一个独立的功能,我们称为 复合设备(Composite Device) 。例如,带鼠标功能的多媒体键盘可以实现鼠标与键盘的功能,带录音与扬声器功能的设备可以实现录制与播放功能。
无论一个复合设备有多少个接口,主机只会给该设备分配一个地址,但对于组合设备而言,主机会给每个功能(设备)分配一个地址。需要注意的是: 有些资料在阐述“组合(设备)”与“复合(设备)”概念时,对应的英文与本书相反,这是因为“复合”的概念在国内应用得更广泛一些,且大多数场合对应“Composite”,所以本书还是沿用惯例,其实“Compound”也可以理解为“复合”,这只是笔者对英文翻译的理解与统一处理,大家了解一下即可。
第5个字段(bConfigurationValue)表示配置值。我们已经提过,一个USB设备可以有多个配置,该配置值就是每个配置的标识。设备只有在配置完成后才算完成总线枚举过程,主机在枚举过程中会读取设备支持的所有配置描述符,最后才发送命令来选择一个配置。如果选择的配置值与该字段值一样,说明该值对应的配置被激活。
第6个字段(iConfiguration)为描述该配置字符串的索引值。如果没有,可以设置为0。第7个字段(bmAttributes)表示USB设备的配置特性,它是基于位映射的字段(一个或多个数据位代表一定的功能配置),其意义如图15.1所示。
图15.1 配置特性
配置特性中的 最高位D 7 由于历史原因必须设置为1 ,而低5位全为0。D 5 表示设备是否支持远程唤醒。我们知道,主机可以通过命令控制设备的状态,即可通过发起总线活动而唤醒设备。但是,设备同样也可以唤醒主机。例如,通过USB键盘唤醒处于待机状态的PC,USB规范将其称为远程唤醒(Remote Wakeup)。在配置描述符中,USB设备会将“是否支持远程唤醒的能力”报告给主机。如果将D 5 位设置为1,表示支持远程唤醒;设置为0表示不支持远程唤醒。
D 6 位用来配置设备的供电模式。大家可能都知道,USB设备的供电方式有两种,其中一种直接使用USB电源,USB规范将其称为 总线供电 (Bus-Powered),适用于电流消耗不大的设备。例如,USB鼠标、USB键盘、USB操纵杆、简单的USB集线器、U盘就是应用的典型。还有一种设备的主要供电来源并不是USB电源,它单独配有供电电源接口,USB规范将其称为 自供电 (Self-Powered),适用于电流消耗比较大的设备。例如,很多硬盘盒(尤其是与3.5寸硬盘配套的)具备USB与供电电源两个接口,因为USB总线可以提供的最大电流为500mA,但硬盘的供电电流(尤其是刚启动时)可能会远大于此值,所以通常设置为自供电方式。
当然,以上只是对供电模式的简要介绍,还有一些细节也值得我们注意。USB规范根据消耗的电流大小进一步将设备分为低功耗(Low-Power)与高功耗(High-Power)两种,前者消耗的电流不大于100mA,后者最大可达500mA。这里所涉及的电流值指的是绝对最大值(不是平均值),USB规范还将100mA定义为一个单位负载(Unit Load),大家了解一下即可。
所有设备默认都是低功耗设备 。只有在软件的控制下才能完成到高功耗设备的切换。但在完成切换之前,软件首先得保证有足够的电流可供使用。(根)集线器是USB设备所需电流的来源之一,总线供电设备可以被分为低功耗设备与高功耗设备,低功耗设备应该能够在VBUS电压低至4.4V(从线缆插头端的测量值)时也能够正常工作。刚刚提过的USB鼠标与键盘就是经典的低功耗总线供电设备,相应的系统框图如图15.2所示,其中的调压单元等同于图4.1中的LM1117,它用来对VBUS电源进行必要的降压转换。如果功能设备本身可以直接使用VBUS电源,调压单元是可选的。
图15.2 低功耗总线供电设备的系统框图
高功耗总线供电设备的系统框图如图15.3所示,它在未完成配置前仍然是低功耗设备,所以最多允许消耗不超过100mA的电流。而在接下来的总线枚举过程中,主机会通过配置描述符获取该设备需要的电流,并且确定 剩下 (因为其他连接的设备也需要电流,而总电流是有限的)可以提供的电流是否足够。如果确认电流裕量足够,就会最终完成设备配置而使其进入高功耗状态,此后允许消耗不超过500mA的电流。
图15.3 高功耗总线供电设备的系统框图
以上我们讨论的都是功能设备。实际上,集线器也可以分为总线供电与自供电两种。组合(Compound)总线供电集线器的框图如图15.4所示。
图15.4 组合总线供电集线器的框图
“组合”的命名来源就是那个不可拆卸的功能设备。需要注意的是,图15.4中的开关模块(Switch)主要用来控制下行口电源,因为我们已经提过, 所有设备默认都是低功耗设备 ,集线器控制器提供可由主机软件控制的开关信号,它可以在集线器刚上电时将开关模块关闭(以防止下行口消耗过多总线电流而使总线枚举失败),待配置完成后才再使能开关模块。
自供电集线器设备本身具备额外的供电电源,我们称其为 本地电源 (Local Power),所有下行口以及不可拆卸的功能设备的供电都来源于本地电源,可以支持的最大下行口数量仅受限于 集线器可分配的地址数量 与 本地电源的供电电流大小 ,因为它们不消耗USB总线提供的电流。那么集线器控制芯片的电源供电应该取自USB总线还是局部电源呢?两者都可以!但是,使用USB总线电源时,即便本地电源处于未供电状态,主机仍然能够与集线器控制器通信,这使得区分 未连接 与 未供电 设备成为可能。当然,从USB总线消耗的电流总是不应该大于100mA。
组合自供电集线器的系统框图如图15.5所示,它可以供给比总线供电集线器要大得多的电流量,所以为了安全起见,主机与自供电集线器必须具备过流保护功能(over-current protection),集线器应该具备检测过流条件并报告给软件的方式,这样才能够进一步切断或降低受影响的下行口所消耗的电流。当然,出于成本的考虑,很多集线器可能并没有这么做。
图15.5 组合自供电集线器的系统框图
另外,当本地电源断开(或电池能源逐渐消耗)时,自供电集线器设备可能会出现供电不足的情况,此时集线器可能会尝试 重新枚举为总线供电集线器 ,如果此时下行口连接了消耗电流比较大的设备,很可能会超出总线可以提供的最大电流,为此集线器也应该存在断开下行口供电的开关模块,它包含在电流限制(Current Limit)模块中。当然,有些集线器本身支持两种供电方式,此时需要增加控制开关电路将总线电源与本地电源进行隔离,我们会在第50章详细探讨。
好的,以上所述已经足够我们理解供电模式了。如果你将配置特性中的D 6 位设置为0,表示使用总线电源,那么这样会简化USB设备的硬件设计;如果你将D 6 位设置为1,则意味着你需要给设备额外配置电源供电电路。在清单2.2中,其被设置为1,这意味着我们的开发板应该自己提供单独的电源电路,但是图4.1所示的电路中并没有,那为什么我们的开发板仍然能够正常工作呢?因为刚刚已经提过,自供电设备如果由于电源断开而导致电流不足时会尝试重新枚举为总线供电集线器。也就是说,不管使用哪种供电模式,你总是可以指定设备从总线获得电流,具体的电流大小是由第9个字段(MaxPower)给出的,它以2mA为一个单位。例如,清单12.2中该字段为0x32(50),则表示相应的电流为50×2mA=100mA。
最后我们看一下从主机端看到的游戏操纵杆的配置描述符信息,如表15.2所示,读者可对照清单12.2自行分析,此处不再赘述。
表15.2 游戏操纵杆的配置描述符信息