每次在主机控制器和 USB 设备之间移动数据时,都会发生传输。 通常,USB 传输可大致分为控制传输和数据传输。 所有 USB 设备都必须支持控制传输,并且可以支持用于数据传输的端点。 每种类型的传输都与设备缓冲区USB 端点 的类型相关联。 控制传输与默认端点相关联,数据传输使用单向端点。 数据传输类型使用中断、批量和常时等量端点。 USB 驱动程序堆栈为设备支持的每个端点创建名为 管道 的信道。 管道的一端是设备的端点。 管道的另一端始终是主控制器。
在向设备发送 I/O 请求之前,客户端驱动程序必须从 USB 设备检索有关配置、接口、端点、供应商和类特定描述符的信息。 此外,驱动程序还必须配置设备。 设备配置涉及诸如在每个接口中选择配置和备用设置等任务。 每个备用设置都可以指定一个或多个可用于数据传输的 USB 端点。
客户端驱动程序配置设备后,驱动程序可以访问 USB 驱动程序堆栈为当前所选备用设置中的每个端点创建的管道句柄。 若要将数据传输到端点,客户端驱动程序通过设置特定于请求类型的 URB 的格式来创建请求。
关于默认端点
所有 USB 设备必须支持至少一个名为“默认端点”的端点。 任何以默认端点为目标的传输都称为“控制传输”。 控制传输的目的是使主机能够获取设备信息、配置设备或执行特定于设备的控制操作。
默认端点有以下特征:
- 默认端点的地址为 0;
- 默认端点是双向的,也就是说,在一次传输过程中,主机可以向端点发送数据并从其接收数据;
- 默认端点在设备级别可用,不在设备的任何接口中定义;
- 一旦在主机和设备之间建立连接,默认端点就处于活动状态。 甚至在选择配置之前,它就已经处于活动状态;
- 默认端点的数据包最大大小取决于设备的总线速度。 低速,8 字节;全速和高速,64 字节;超高速,512 字节;
控制传输
由于控制传输是高优先级传输,因此会由主机在总线上保留一定量的带宽。 将为低速和全速设备保留 10% 的带宽;为高速和超高速传输设备保留 20% 的带宽。 现在,让我们看看控制传输的布局。
控制传输分为三个事务:设置事务 、数据事务 、状态事务 。 每个事务包含三类数据包:令牌数据包、数据数据包、握手数据包。
某些字段通用于所有数据包。 这些字段是:
- “同步”字段,指示数据包的开始;
- 数据包标识符 (PID),指示数据包的类型、事务的方向、事务是成功还是失败(如果是握手数据包);
- EOP 字段,指示数据包的结束;
其他字段取决于数据包的类型。
令牌数据包
每个设置事务都以令牌数据包开头。 下面是该数据包的结构。 主机始终发送令牌数据包。
PID 值指示令牌数据包的类型。 下面是可能的值:
- SETUP:指示控制传输中设置事务的开始;
- IN:指示主机在从设备请求数据;
- OUT:指示主机在将数据发送到设备;
- SOF:指示帧的开始。 此类型的令牌数据包包含一个 11 位的帧号。 主机发送 SOF 数据包。 发送此数据包的频率取决于总线速度。 对于全速总线,主机每隔 1 毫秒发送一次数据包;对于高速总线,则每隔 125 微秒发送一次;
数据数据包
紧跟着令牌数据包的是包含有效负载的数据数据包。 每个数据数据包能够包含的字节数取决于默认终结点的数据包最大大小。 数据数据包可以由主机或设备发送,具体取决于传输的方向。
握手数据包
紧跟着数据数据包的是握手数据包。 此数据包的 PID 指示是主机还是设备接收了数据包。 握手数据包可以由主机或设备发送,具体取决于传输的方向。
可以使用任何 USB 分析器(例如 Beagle、Ellisys、LeCroy USB 协议分析器)来查看事务和数据包的结构。 分析器设备显示如何通过线路将数据发送到 USB 设备或从其接收数据。 在此示例中,让我们检查由 LeCroy USB 分析器捕获的某些跟踪。 此示例仅供参考, 不表示 Microsoft 的认可。
设置事务
始终由主机启动控制传输。 为此,主机会发送设置事务。 此事务包含名为“设置令牌”的令牌数据包,后跟一个 8 字节的数据数据包。 以下屏幕截图显示了一个示例性的设置事务。
在前面的跟踪中,主机通过发送设置令牌数据包 #434 来启动 由H 指示控制传输。 请注意,PID 指定的 SETUP 表示一个设置令牌。 PID 后跟设备地址和终结点地址。 对于控制传输,该终结点地址始终为 0。
接下来,主机发送数据包#435。 PID 为 DATA0,该值用于数据包排序(在后面讨论)。 PID 后跟 8 个字节,其中包含有关此请求的主要信息。 这 8 个字节指示请求的类型和缓冲区(设备将在其中写入响应)的大小。
所有字节以相反顺序接收。我们会看到以下字段和值:
因此,我们可以得出结论:在此控制(读取)传输中,主机发送请求来检索设备描述符,并指定 18 个字节作为保存该描述符所需的传输长度。 设备发送这 18 个字节的方式取决于默认终结点可以在一个事务中发送多少数据。 该信息包含在设备描述符中,由设备在数据事务中返回。
作为响应,设备发送握手数据包#436。 请注意,PID 值为 ACK(ACK 数据包)。 这表示设备确认了此事务。
数据事务
现在,让我们看看设备在响应请求时返回的内容。 实际数据在数据事务中传输。
下面是数据事务的跟踪。
在接收到 ACK 数据包后,主机会启动数据事务。 为了启动事务,它会发送一个令牌数据包 #450 ,其方向为 IN ,称为 IN token。
作为响应,设备发送 IN 令牌后面的数据包#451。 此数据数据包包含实际的设备描述符。 第一个字节指示设备描述符的长度,即 18 个字节 (0x12)。 此数据数据包中的最后一个字节指示默认终结点支持的数据包最大大小。 在此示例中,我们看到设备可以通过其默认终结点一次发送 8 个字节。
默认终结点的数据包最大大小取决于设备的速度。 高速设备的默认终结点为 64 个字节;低速设备为 8 个字节。
主机通过向设备发送 ACK 数据包 #452来确认数据事务。
让我们计算返回的数据量。 在设置事务中数据包 #435的 wLength 字段中,主机请求了 18 个字节。 在数据事务中,我们看到从设备收到的只有设备描述符的前 8 个字节。 那么,主机如何接收存储在剩余的 10 个字节中的信息? 设备分两个事务这样做:先是 8 个字节,然后是最后的 2 个字节。
主机知道了默认终结点的数据包最大大小以后,就会启动新的数据事务,根据数据包大小请求下一部分。
下面是下一数据事务:
主机通过发送 IN 令牌 #463 并从设备请求接下来的 8 个字节来启动上述数据事务。 设备使用数据包 #464 进行响应,其中包含设备描述符接下来的 8 个字节。
收到 8 个字节后,主机会向设备发送 ACK 数据包 #465。
接下来,主机在另一数据事务中请求最后的 2 个字节,如下所示:
因此,我们看到,为了将 18 个字节从设备传输到主机,主机会跟踪传输的字节数并启动三个数据事务 (8+8+2)。
请注意数据事务 19、23、26 中数据包的 PID。 PID 在 DATA0 和 DATA1 之间交替变换。 该顺序称为数据切换。 在有多个数据事务的情况下,数据切换用于验证数据包顺序。 此方法可确保数据数据包不重复或丢失。
将合并的数据数据包映射到设备描述符的结构,我们看到以下字段和值:
检查这些值即可获得设备的一些初步信息。 设备是低速 USB 麦克风。 默认终结点的数据包最大大小为 8 个字节。 设备支持一种配置。
状态事务
最后,主机会启动最后一个事务:状态事务,从而完成控制传输。
主机使用 OUT 令牌数据包 (#481) 启动事务。 此数据包的目的是验证设备是否已发送所有请求的数据。 在此状态事务中,不发送数据数据包。 设备使用 ACK 数据包进行响应。 如果发生错误,PID 可能为 NAK 或 STALL。