分配和构建 URB

本主题介绍 USB 客户端驱动程序如何在向 Microsoft 提供的 USB 驱动程序堆栈发送请求之前使用 Windows 驱动程序模型 (WDM) 驱动程序例程分配和格式化 URB。

客户端驱动程序使用 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 会提供帮助程序例程(通过 Usbd.sys 导出),这些例程会分配和格式化 URB 结构。例如,USBD_CreateConfigurationRequestEx 例程会为某个 URB 结构分配内存,为 select-configuration 请求格式化 URB,以及将 URB 结构的地址返回到客户端驱动程序。 但是,帮助程序例程不能用于所有类型的请求。

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

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

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

Windows 8 中的 URB 分配

Windows 8 的 WDK 提供了新的静态库 Usbdex.lib,该库会导出用于分配、格式化以及释放 URB 的例程。另外,还有一种将 URB 与 IRP 关联的新方法。这些新例程可以由适用于 Windows Vista 和更高版本的 Windows 的客户端驱动程序调用。

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

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

Windows 8 的 WDK 中提供了以下例程。这些例程在 Usbdlib.h 中进行定义。

前述列表中的分配例程会返回指向新 URB 结构的指针,该结构由 USB 驱动程序堆栈进行分配。根据 Windows 加载 USB 驱动程序堆栈的版本,可以将 URB 结构与不透明的“URB 上下文”进行配对。URB 上下文是有关 URB 的信息块。无法查看 URB 头的内容;该信息旨在供 USB 驱动程序堆栈在内部使用以改进 URB 跟踪和处理。URB 上下文“仅”供 Windows 8 的 USB 驱动程序堆栈使用。

如果 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 中可用。在 Windows 8 的 WDK 中可用。
针对 Windows 7 和之前版本的操作系统针对 Windows Vista 和更高版本的操作系统
创建 URB...根据请求,客户端驱动程序会分配 URB 结构并格式化该结构。

客户端驱动程序在堆栈上分配 URB 结构,或该驱动程序通过调用 ExAllocatePoolWithTag 在非分页缓冲池中分配该结构。

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

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

客户端驱动程序调用 USBD_UrbFree

 

相关主题

发送请求到 USB 设备

 

 

显示:
© 2015 Microsoft