客户端驱动程序在一个 URB_FUNCTION_SELECT_CONFIGURATION 类型的 USB 请求块 (URB) 中发送选择配置请求。本主题中的过程介绍了如何使用 USBD_SelectConfigUrbAllocateAndBuild 例程来构建该 URB。该例程为 URB 分配内存,针对一个选择配置请求格式化该 URB,并将该 URB 的地址返回到客户端驱动程序。
也可以分配一个 URB 结构,然后手动或调用 UsbBuildSelectConfigurationRequest 宏来格式化该 URB。
先决条件
在 Windows 8 中,USBD_SelectConfigUrbAllocateAndBuild 取代了 USBD_CreateConfigurationRequestEx。
发送一个选择配置请求之前,你必须有一个 USBD 句柄,用于客户端驱动程序向 USB 驱动程序堆栈的注册。要创建一个 USBD 句柄,可以调用USBD_CreateHandle。
确保你获得了要选择的配置的配置描述符(USB_CONFIGURATION_DESCRIPTOR 结构)。通常,你提交一个 URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 类型的 URB(参阅 _URB_CONTROL_DESCRIPTOR_REQUEST),以检索有关设备配置的信息。
说明
步骤 1: 创建一个具有 USBD_INTERFACE_LIST_ENTRY 结构的数组。
1、获取配置中的接口数量。此信息包含在 USB_CONFIGURATION_DESCRIPTOR 结构的 bNumInterfaces 成员中。
2、创建一个 USBD_INTERFACE_LIST_ENTRY 结构的数组。该数组中的元素数量必须比接口的数量多一个。调用 RtlZeroMemory 来初始化数组。客户端驱动程序在具有 USBD_INTERFACE_LIST_ENTRY 结构的数组中指定每个接口中要启用的备用设置。
每个结构的 InterfaceDescriptor 成员指向了包含该备用设置的接口描述符。
每个结构的 Interface 成员指向一个 USBD_INTERFACE_INFORMATION 结构,该结构的 Pipes 成员中包含管道信息。Pipes 存储有关备用设置中已定义的每个终结点的信息。
3、获取配置中每个接口的接口描述符(或其备用设置)。你可以通过调用 USBD_ParseConfigurationDescriptorEx 获取这些接口描述符。
关于 USB 复合设备的函数驱动程序: 如果 USB 设备是复合设备,则由 Microsoft 提供的 USB 通用父驱动程序 (Usbccgp.sys) 来选择配置。客户端驱动程序是复合设备的函数驱动程序之一,它不能更改配置,但仍可通过 Usbccgp.sys 发送 select-configuration 请求。
发送该请求之前,客户端驱动程序必须提交 URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 请求。在响应中,Usbccgp.sys 将检索部分配置描述符,其中只包含接口描述符以及与客户端驱动程序为其加载的特定函数相关的描述符。部分配置描述符的 bNumInterfaces 字段中报告的接口数量小于为整个 USB 复合设备定义的接口总数。另外,在部分配置描述符中,接口描述符的 bInterfaceNumber 指示相对于整个设备的实际接口数量。例如,在 Usbccgp.sys 可能报告的第一个接口的部分配置描述符中,bNumInterfaces 值为 2,而 bInterfaceNumber 值为 4。注意接口数量大于所报告的接口数量。
在枚举部分配置中的接口时,请避免通过基于接口的数量计算接口数量来搜索接口。在上述示例中,如果在从零开始、以 (bNumInterfaces - 1) 结束,并且在每次迭代中按接口索引(在 InterfaceNumber 参数中指定)递增的循环中调用 USBD_ParseConfigurationDescriptorEx,则该例程将无法获取正确的接口。相反,请确保通过在 InterfaceNumber 中传递 -1 来搜索配置描述符中的所有接口。有关实现详细信息,请参阅本部分中的代码示例。有关 Usbccgp.sys 如何处理由客户端驱动程序发送的 select-configuration 请求的信息,请参阅配置 Usbccgp.sys 以选择非默认 USB 配置。
4、对于数组中的每个元素(除了最后一个元素),将 InterfaceDescriptor 成员设置为一个接口描述符的地址。对于数组中的第一个元素,将InterfaceDescriptor 成员设置为表示配置中首个接口的接口描述符的地址。类似地,对于数组中的第 n 个元素,将 InterfaceDescriptor 成员设置为表示配置中第 n 个接口的接口描述符的地址。最后一个元素的 InterfaceDescriptor 成员必须设置为 NULL。
步骤 2: 获得 USB 驱动程序堆栈分配的一个 URB 的指针。
接下来,通过指定要选择的配置和填充的 USBD_INTERFACE_LIST_ENTRY 结构数组,调用 USBD_SelectConfigUrbAllocateAndBuild。该例程执行以下任务:
创建一个 URB 并向其中填入有关指定的配置、它的接口和终结点的信息,将请求类型设置为 URB_FUNCTION_SELECT_CONFIGURATION。
在该 URB 内,为客户端驱动程序指定的每个接口描述符分配一个 USBD_INTERFACE_INFORMATION 结构。
将调用方提供的 USBD_INTERFACE_LIST_ENTRY 数组的第 n 个元素的 Interface 成员设置为 URB 中相应USBD_INTERFACE_INFORMATION 结构的地址。
初始化 InterfaceNumber、AlternateSetting、NumberOfPipes、Pipes[i].MaximumTransferSize 和 Pipes[i].PipeFlags 成员。
注意 在 Windows 7 和早期版本中,客户端驱动程序通过调用 USBD_CreateConfigurationRequestEx 为 select-configuration 请求创建 URB。在 Windows 2000 中,USBD_CreateConfigurationRequestEx 将 Pipes[i].MaximumTransferSize 初始化为单个 URB 读/写请求的默认最大传输大小。客户端驱动程序可以在 Pipes[i].MaximumTransferSize 中指定不同的最大传输大小。在 Windows XP、Windows Server 2003 和更高版本的 *** 作系统中,USB 堆栈将忽略此值。有关 MaximumTransferSize 的详细信息,请参阅设置 USB 传输和数据包大小。
步骤 3: 将 URB 提交到 USB 驱动程序堆栈。
要将 URB 提交到 USB 驱动程序堆栈,客户端驱动程序必须发送一个 IOCTL_INTERNAL_USB_SUBMIT_URB I/O 控制请求。有关提交 URB 的信息,请参阅如何提交 URB。
收到 URB 后,USB 驱动程序填充每个 USBD_INTERFACE_INFORMATION 结构的剩余成员。具体来讲,会为 Pipes 数组成员填入与接口终结点相关联的管道的信息。
步骤 4: 请求完成时,检查 USBD_INTERFACE_INFORMATION 结构和 URB。
USB 驱动程序堆栈完成请求的 IRP 后,堆栈在 USBD_INTERFACE_LIST_ENTRY 数组中返回备用设置和相关接口的列表。
1、每个 USBD_INTERFACE_INFORMATION 结构的 Pipes 成员指向一个 USBD_PIPE_INFORMATION 结构数组,该数组包含与该特定接口的每个终结点相关联的管道的信息。客户端驱动程序可从 Pipes[i].PipeHandle 获取管道句柄并使用它们将 I/O 请求发送到特定管道。Pipes[i].PipeType成员指定该管道支持的终结点和传输类型。
2、在 URB 的 UrbSelectConfiguration 成员中,USB 驱动程序堆栈返回一个句柄,你可以使用该句柄通过提交另一个 URB_FUNCTION_SELECT_INTERFACE 类型的 URB(选择接口请求)来选择一个备用接口设置。要为该请求分配和构建 URB 结构,可以调用USBD_SelectInterfaceUrbAllocateAndBuild。
如果没有足够的带宽来支持已启用的接口中的常时等量、控制和中断终结点,选择配置请求和选择接口请求可能失败。在此情况下,USB 总线驱动程序将 URB 头文件的 Status 成员设置为 USBD_STATUS_NO_BANDWIDTH。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)