分配和构建 URB

USB 客户端驱动程序可以使用 Windows 驱动程序模型 (WDM) 驱动程序例程来分配 URB 并格式化 URB,然后再将请求发送到 Microsoft 提供的 USB 驱动程序堆栈。

客户端驱动程序使用 URB 打包 USB 驱动程序堆栈中较低级驱动程序处理请求所需的所有信息。 在 Windows 操作系统中,URB 在 URB 结构中描述。

Microsoft 为 USB 客户端驱动程序提供了例程库。 通过使用这些例程,USB 客户端驱动程序可以为某些指定操作生成 URB 请求,并将其转发到 USB 堆栈中。 如果愿意,可以将客户端驱动程序设计为为支持的操作调用库例程,而不是生成自己的 URB 请求。

Windows 7 及更早版本中的 URB 分配

若要使用适用于 Windows 7 及更早版本的 Windows 的 Windows 驱动程序工具包 (WDK) 中包含的例程发送 USB 请求,客户端驱动程序通常会分配和填充 URB 结构,将 URB 结构与新的 IRP 相关联,并将 IRP 发送到 USB 驱动程序堆栈。

对于某些类型的请求,Microsoft 提供 (由分配 URB 结构的Usbd.sys) 导出的帮助程序例程。 例如, USBD_CreateConfigurationRequestEx 例程为 URB 结构分配内存,为选择配置请求设置 URB 格式,并将 URB 结构的地址返回到客户端驱动程序。 但是,帮助程序例程不能用于所有类型的请求。

Microsoft 还提供了为某些类型的请求设置 URL 格式的宏。 对于这些宏,客户端驱动程序必须通过调用 ExAllocatePoolWithTag 来分配 URB 结构,或者在堆栈上分配 结构。 例如,在客户端驱动程序分配 URB 后,驱动程序可以调用 UsbBuildSelectConfigurationRequest 来格式化选择配置请求的 URB 或清除配置。

对于其他请求,客户端驱动程序必须根据请求类型,通过设置 URB 结构的各个成员来手动分配 和格式化 URB

USB 请求完成后,客户端驱动程序必须释放 URB 结构。 如果在堆栈上分配 URB,则 URB 在超出范围时释放。 如果在非分页池中分配 URB,则客户端驱动程序必须调用 ExFreePool 才能释放 URB。

Windows 8中的 URB 分配

WDK for Windows 8 提供了一个新的静态库 Usbdex.lib,用于导出用于分配、格式化和释放 URL 的例程。 此外,还有一种将 URB 与 IRP 相关联的新方法。 新的例程可由面向 Windows Vista 和更高版本的 Windows 的客户端驱动程序调用。

在 Windows Vista 及更高版本上运行的客户端驱动程序必须使用新的例程,以便基础 USB 驱动程序堆栈可以利用某些性能和可靠性改进。 这些改进适用于 Windows 8 中为支持 USB 3.0 设备和主机控制器而引入的新 USB 驱动程序堆栈。 对于 USB 2.0 主控制器,Windows 加载不支持改进的驱动程序堆栈的早期版本。 无论基础驱动程序堆栈的版本或主机控制器支持的协议版本如何,都必须始终调用新的 URB 例程。

在调用任何新例程之前,请确保有一个 USBD 句柄,用于向 USB 驱动程序堆栈注册客户端驱动程序。 若要获取 USBD 句柄, 请调用 USBD_CreateHandle

WDK 提供以下例程,用于Windows 8。 这些例程在 Usbdlib.h 中定义。

前面列表中的分配例程返回指向由 USB 驱动程序堆栈分配的新 URB 结构的指针。 根据 Windows 加载的 USB 驱动程序堆栈的版本, URB 结构可以与不透明的 URB 上下文配对。 URB 上下文是有关 URB 的信息块。 无法查看 URB 标头的内容;这些信息旨在由 USB 驱动程序堆栈在内部使用,以改善 URB 跟踪和处理。 URB 上下文仅由 USB 驱动程序堆栈用于Windows 8。 如果 URB 上下文可用,USB 驱动程序堆栈会使用它使 URB 处理更安全、更高效。 例如,USB 驱动程序堆栈必须确保客户端驱动程序不会提交 URB,然后尝试在第一个请求完成之前重复使用同一 URB。 为了检测此类错误,USB 驱动程序堆栈会将状态信息存储在 URB 上下文中。 如果没有状态信息,USB 驱动程序堆栈将不得不将传入的 URB 与当前正在进行的所有 URB 进行比较。 当客户端驱动程序尝试释放 URB 时,USB 驱动程序堆栈也会使用状态信息。 在释放 URB 之前,USB 驱动程序堆栈会验证状态,以确保 URB 未挂起。

URB 上下文提供用于存储额外 URB 信息的官方机制。 使用 URB 上下文比根据需要分配额外的内存或在 URB 结构的保留成员中存储额外信息更可取。 USB 驱动程序堆栈在非分页池中分配 URB 及其关联的 URB 上下文,以便将来如果需要更大的 URB 上下文,唯一需要调整的是池分配的大小。

URB 例程迁移

下表汇总了 URB 例程中的更改。

用例 适用于 Windows 7 及更早版本的 WDK 在 WDK 中可用于 Windows 8 及更高版本
  面向 Windows 7 和早期版本的操作系统 面向Windows 8及更高版本的操作系统
若要创建 URB... 客户端驱动程序分配 URB 结构并根据请求设置结构的格式。

客户端驱动程序在堆栈上分配 URB 结构,或者驱动程序通过调用 ExAllocatePoolWithTag 在非分页池中分配结构。
客户端驱动程序调用 USBD_UrbAllocate ,并接收指向由 USB 驱动程序堆栈分配的新 URB 结构的指针。 URB 可能与 URB 上下文相关联,具体取决于基础 USB 驱动程序堆栈的 USBD 接口版本。
若要为选择配置请求创建 URB... 客户端驱动程序调用 USBD_CreateConfigurationRequestEx 例程,该例程返回指向由 USB 驱动程序堆栈创建和格式化的新 URB 的指针。 客户端驱动程序调用 USBD_SelectConfigUrbAllocateAndBuild 并接收指向新 URB 结构的指针,该结构由 USB 驱动程序堆栈) (分配和格式化。 URB 可能与 URB 上下文相关联,具体取决于基础 USB 驱动程序堆栈的 USBD 接口版本。
若要为选择接口请求创建 URB... 客户端驱动程序分配 URB 结构,并使用 _URB_SELECT_INTERFACE 结构为 USB 设备定义选择接口命令的格式。 客户端驱动程序调用 USBD_SelectInterfaceUrbAllocateAndBuild 并接收指向新 URB 结构的指针,该结构 (为 USB 驱动程序堆栈) 选择接口请求分配和格式化。 URB 可能与 URB 上下文相关联,具体取决于基础 USB 驱动程序堆栈的 USBD 接口版本。
将 URB 与 IRP 相关联... 客户端驱动程序通过调用 IoGetNextIrpStackLocation 获取指向下一个 IRP 堆栈位置的指针。 然后,客户端驱动程序手动将堆栈位置的 Parameters.Others.Argument1 成员设置为 URB 结构的地址。 客户端驱动程序通过调用 IoGetNextIrpStackLocation 获取指向下一个 IRP 堆栈位置的指针。 然后,客户端驱动程序调用 USBD_AssignUrbToIoStackLocation ,将 URB 与堆栈位置相关联。
若要发布 URB... 如果客户端驱动程序在堆栈上分配 URB,则变量在请求完成后超出范围。

若要释放客户端驱动程序或非分页池中分配的 USB 驱动程序堆栈的 URB 结构,客户端驱动程序会调用 ExFreePool
客户端驱动程序调用 USBD_UrbFree