本文提供有关仔细管理 USB 带宽的指导。 每个 USB 客户端驱动程序都有责任尽量减少其使用的 USB 带宽,并尽快将未使用的带宽返回到免费带宽池。
为什么我的 USB 驱动程序出现带宽错误?
USB 总线上的带宽竞争来自多个源,包括硬件和软件。 很难准确预测 USB 客户端驱动程序的可用带宽量。 USB 主机控制器需要一定数量的带宽来完成其作。 所需的量取决于控制器是否高速。 它因系统而异。 以高速运行的 USB 中心有时必须转换高速上游端口和下游低速设备之间的事务,此转换过程会消耗带宽。 但是,事务转换是否需要带宽取决于连接的设备和设备树的拓扑类型。
带宽资源最严重的压力通常来自垄断带宽的 USB 客户端驱动程序。 系统基于先来先得服务分配带宽。 如果第一个 USB 驱动程序加载请求所有可用带宽,则以后加载的 USB 驱动程序不允许其设备的任何带宽。 系统无法配置设备,无法枚举该设备。 由于枚举失败的原因并不明显,因此用户的体验不佳。
有时,客户端驱动程序会用高速中断传输耗尽可用带宽。 但迄今为止,最常见的情况是,客户端驱动程序为时空传输分配过多带宽,然后无法及时释放带宽。 系统会保留分配的带宽,直到请求其终结点的驱动程序关闭其终结点(通过打开另一终结点),或为其分配带宽的设备被删除。 系统不会为批量传输分配有保证的带宽,因此大容量传输绝不是枚举失败的原因。 但是,批量传输设备的性能取决于为进行周期性(等时和中断)传输的设备分配多少带宽。
USB 2.0 规范要求同步设备在其默认接口设置上具有零带宽端点。 这可确保在函数驱动程序打开非默认接口之前,不会为设备保留带宽,这有助于防止在设备配置期间过度带宽请求导致的枚举失败。 它不会阻止客户端驱动程序在配置其设备后分配过多带宽,从而阻止其他设备正常运行。
正确带宽管理的关键是,系统中执行时序传输的每个 USB 设备必须为每个包含时序终结点的接口提供多个备用(Alt)设置,并且客户端驱动程序必须合理地使用这些 Alt 设置。 客户端驱动程序应首先请求具有最高带宽的接口设置。 如果请求失败,客户端驱动程序应逐步请求带宽越来越小的接口设置,直到请求成功。
例如,假设网络摄像头设备具有以下接口:
接口 0 (默认接口设置:默认设置中没有具有非零时序带宽的终结点)
同步终端 1:最大数据包大小 = 0 字节
等时终结点 2:最大包大小 = 0 字节
接口 0 Alt 设置 1
同步端点 1:最大数据包大小=256 字节
等时终结点 2:最大数据包大小 = 256 字节
接口 0 Alt 设置 2
同步端点 1:最大数据包大小 = 512 字节
同步终端 2:最大数据包大小 = 512 字节
网络摄像头的驱动程序将网络摄像头配置为在初始化时使用默认接口设置。 默认设置没有同步带宽,因此在初始化期间使用默认设置可以避免摄像头因请求同步带宽失败而无法枚举的风险。
当客户端驱动程序准备好执行时空传输时,它应尝试使用 Alt 设置 2,因为 Alt 设置 2 具有最大的数据包大小。 如果请求失败,驱动程序可以使用 Alt 设置 1 进行第二次尝试。 由于 Alt 设置 1 需要更少的带宽,因此即使第一个请求失败,此请求也可能成功。 在放弃之前,多个 Alt 设置允许驱动程序进行多次尝试。
网络摄像头空闲后,可以通过再次选择默认设置,将分配的带宽返回到免费带宽池。
用户可以通过检查 Windows 设备管理器中的控制器属性来查看 USB 控制器分配的带宽。 选择控制器的属性,然后在“高级”选项卡下查看。此数据读取并未指示 USB 集线器为事务转换分配了多少带宽。
报告 USB 控制器带宽使用情况的设备管理器功能在 Windows XP 中无法正常工作。
USB 传输和数据包大小
本文介绍各种版本的 Windows作系统中允许的 USB 传输大小。
最大传输大小
最大传输大小指定 USB 驱动程序堆栈中的硬编码限制。 由于系统资源限制,低于这些限制的传输大小可能会失败。 若要避免这些类型的故障并确保在所有版本的 Windows 之间兼容,请避免使用大型传输大小进行 USB 传输。
注释
USBD_PIPE_INFORMATION结构的 MaximumTransferSize 成员已过时。 USB 驱动程序堆栈忽略复合设备和非复合设备 MaximumTransferSize 中的值。
在 Windows 2000 中,USB 驱动程序堆栈将 MaximumTransferSize 设置为 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE。 客户端驱动程序可以在配置设备时设置较小的值。 对于复合设备,每个函数的客户端驱动程序只能更改非默认接口设置中管道的 MaximumTransferSize 。
USB 传输大小受以下限制:
| 传输管道 | Windows 8.1、Windows 8 | Windows 7、Windows Vista | Windows XP、Windows Server 2003 | Windows 2000 |
|---|---|---|---|---|
| 控制 | 超速和高速 64K (xHCI) 4K 适用于全速和低速(xHCI、EHCI、UHCI、OHCI) 对于 UHCI,默认终结点上为 4K;非默认控制管道上为 64K |
高速 64K (EHCI) 全速和低速 4K(EHCI、UHCI、OHCI) 对于 UHCI,默认端点上为 4K,非默认控制管道上为 64K(UHCI) |
高速 64K (EHCI) 支持全速和低速传输的 4K 视频(EHCI、UHCI、OHCI) 对于 UHCI,默认端点为 4K;非默认控制管道为 64K(UHCI) |
默认端点上的 4K;非默认控制通道上的 64K(OHCI) |
| Interrupt | 4MB 用于 SuperSpeed、 高速、全速和低速(xHCI、EHCI、UHCI、OHCI) | 4MB 用于高速、全速和低速(EHCI、UHCI、OHCI) | 无限制 | 不确定(OHCI) |
| 批量 | SuperSpeed 32MB(xHCI) 高速和全速下的 4MB (xHCI) 用于高速和全速传输的 4MB(EHCI 和 UHCI) 256K 全速 (OHCI) |
4MB 用于高速和全速(EHCI、UHCI) 256K 全速 (OHCI) |
3MB 的带宽用于高速和全速 (EHCI) 不确定 (UHCI) 全速传输速度下速率为256K(OHCI) |
不确定(OHCI) |
| 等时的 | 1024 * wBytesPerInterval 用于 SuperSpeed (xHCI) (请参阅 USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR) 1024 * MaximumPacketSize 用于高速传输(xHCI,EHCI) 256 * 全速模式下的最大数据包大小(xHCI,EHCI) 64K 全速(UHCI,OHCI) |
高速(EHCI)环境下的 1024 * MaximumPacketSize 256 * MaximumPacketSize (全速EHCI) 64K 全速(UHCI,OHCI) |
1024 * MaximumPacketSize 用于高速(EHCI) 适用于全速(EHCI)的 256 * MaximumPacketSize 64K 全速(UHCI,OHCI) |
全速 64K(OHCI) |
使用 MaximumTransferSize 限制传输大小不会影响设备消耗的带宽。 客户端驱动程序必须更改接口设置,或限制 USBD_PIPE_INFORMATIONMaximumPacketSize 成员中设置的最大数据包大小。
最大数据包大小
终结点描述符的 wMaxPacketSize 字段定义最大数据包大小。 客户端驱动程序可以在对设备的选择接口请求中调节 USB 数据包大小。 更改此值不会更改设备上的 wMaxPacketSize 。
在请求的URB中,包含用于管道的USBD_PIPE_INFORMATION结构。 在该结构中,
- 修改USBD_PIPE_INFORMATION结构的 MaximumPacketSize 成员。 将其设置为小于或等于当前接口设置的设备固件中定义的 wMaxPacketSize 值的值。
- 在 PipeFlags 成员的 USBD_PIPE_INFORMATION 结构中设置USBD_PF_CHANGE_MAX_PACKET标志。
有关选择接口设置的信息,请参阅 如何为 USB 设备选择配置。
读取传输缓冲区的最大数据包大小限制
当客户端驱动程序发出读取请求时,传输缓冲区必须是最大数据包大小的倍数。 即使驱动程序预期的数据小于最大封包大小,它仍必须请求整个封包。 当设备发送小于最大大小(短数据包)的数据包时,表明传输已完成。
在较旧的控制器上,客户端驱动程序可以替代该行为。 在数据传输 URB 的 TransferFlags 成员中,客户端驱动程序必须设置USBD_SHORT_TRANSFER_OK标志。 该标志允许设备发送小于 wMaxPacketSize 的数据包。
在 xHCI 主机控制器上,USBD_SHORT_TRANSFER_OK 对于批量端点和中断端点被忽略。 在 EHCI 控制器上传输短数据包不会导致错误情况。
在 EHCI 主机控制器上,对于批量终结点和中断终结点,USBD_SHORT_TRANSFER_OK 将被忽略。
在 UHCI 和 OHCI 主机控制器上,如果未为批量传输或中断传输设置USBD_SHORT_TRANSFER_OK,则短数据包传输会停止终结点,并返回传输的错误代码。
使用短数据包分隔写入传输
当写入设备时,USB 驱动程序堆栈在数据包大小上没有施加读取时的那些限制。 某些客户端驱动程序必须频繁传输少量的控制数据来管理其设备。 在这种情况下,将数据传输限制为统一大小的数据包是不切实际的。 因此,驱动程序堆栈不会在数据写入期间为小于终结点最大大小的数据包分配任何特殊意义。 这样,客户端驱动程序就可以将大规模的数据传输拆分为多个小于或等于最大值的 URB。
驱动程序必须使用小于最大大小的数据包结束传输,或者用零长度数据包分隔传输的末尾。 在驱动程序发送小于 wMaxPacketSize 的数据包之前,传输才完成。 如果传输大小正好是最大值的倍数,驱动程序必须发送零长度分隔数据包才能显式终止传输
客户端驱动程序负责根据 USB 规范的要求使用零长度数据包分隔数据传输。 USB 驱动程序堆栈不会自动生成这些数据包。
使用小于 wMaxPacketSize 的数据包限制 USB 数据传输
符合的 USB 2.0 和 USB 1.1 驱动程序必须传输最大大小的数据包(wMaxPacketSize),然后使用小于最大大小的数据包结束传输,或使用零长度数据包分隔传输的末尾。 在驱动程序发送小于 wMaxPacketSize 的数据包之前,传输才完成。 如果传输大小正好是最大值的倍数,驱动程序必须发送零长度分隔数据包才能显式终止传输
设备驱动程序负责根据 USB 规范的要求,使用零长度数据包分隔数据传输。 系统 USB 堆栈不会自动生成这些数据包。