USBD_QueryUsbCapability 函数 (usbdlib.h)

USBD_QueryUsbCapability例程由 WDM 客户端驱动程序调用,以确定基础 USB 驱动程序堆栈和主机控制器硬件是否支持特定功能。 Windows 驱动程序框架 (WDF) 驱动程序的说明: 如果客户端驱动程序是基于 WDF 的驱动程序,则必须调用 WdfUsbTargetDeviceQueryUsbCapability 方法,而不是 USBD_QueryUsbCapability

语法

NTSTATUS USBD_QueryUsbCapability(
  [in]            USBD_HANDLE USBDHandle,
  [in]            const GUID  *CapabilityType,
  [in]            ULONG       OutputBufferLength,
  [in, out]       PUCHAR      OutputBuffer,
  [out, optional] PULONG      ResultLength
);

参数

[in] USBDHandle

客户端驱动程序在上一次调用 USBD_CreateHandle 例程时检索的 USBD 句柄。

[in] CapabilityType

指向 GUID 的指针,该 GUID 表示客户端驱动程序要检索其信息的功能。 可能的 PGUID 值如下所示:

  • GUID_USB_CAPABILITY_CHAINED_MDLS
  • GUID_USB_CAPABILITY_STATIC_STREAMS
  • GUID_USB_CAPABILITY_SELECTIVE_SUSPEND
  • GUID_USB_CAPABILITY_FUNCTION_SUSPEND
  • GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE
  • GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE
  • GUID_USB_CAPABILITY_TIME_SYNC

[in] OutputBufferLength

OutputBuffer 指向的缓冲区的长度(以字节为单位)。

[in, out] OutputBuffer

指向调用方分配的缓冲区的指针。 某些功能请求在输出缓冲区中返回其他信息。 对于这些请求,必须分配缓冲区,并在 OutputBuffer 参数中提供指向缓冲区的指针。 目前,只有静态流功能请求需要 USHORT 类型的输出缓冲区。 缓冲区由 USBD_QueryUsbCapability 填充,每个终结点支持的最大流数。

其他功能请求不需要输出缓冲区。 对于这些请求,必须将 OutputBuffer 设置为 NULL, 将 OutputBufferLength 设置为 0。

[out, optional] ResultLength

指向 ULONG 变量的指针,该变量接收 OutputBuffer 指向的缓冲区中的实际字节数。 调用方可以在 ResultLength 中传递 NULL。 如果 ResultLength 不为 NULL,则接收的值小于或等于 OutputBufferLength 值。

返回值

USBD_QueryUsbCapability例程返回 NT 状态代码。

可能的值包括但不限于下表中列出的状态代码。

返回代码 说明
STATUS_SUCCESS
请求成功,并且支持指定的功能。
STATUS_INVALID_PARAMETER
调用方传递的参数值无效。
  • USBDHandleCapabilityType 为 NULL。
  • OutputBuffer 为 NULL,但 OutputBufferLength 指示非零值。 相反,调用方提供了输出缓冲区,但缓冲区长度为 0。
STATUS_NOT_IMPLEMENTED
基础 USB 驱动程序堆栈不支持指定的功能。
STATUS_NOT_SUPPORTED
主机控制器硬件或 USB 驱动程序堆栈都不支持指定的功能。

注解

Windows 8包含一个新的 USB 驱动程序堆栈,以支持 USB 3.0 设备。 新的 USB 驱动程序堆栈提供了多个定义的新功能,例如,客户端驱动程序可以使用的流支持和链接式 MDL。

客户端驱动程序可以通过调用 IsInterfaceVersionSupported 例程来确定基础 USB 驱动程序堆栈的版本。

仅当基础 USB 驱动程序堆栈硬件支持新功能时,客户端驱动程序才能使用这些新功能。 例如,若要将 I/O 请求发送到与批量终结点关联的特定流,基础 USB 驱动程序堆栈、终结点和主机控制器硬件必须支持静态流功能。 客户端驱动程序 不得 调用 IsInterfaceVersionSupported 并采用驱动程序堆栈的功能。 相反,客户端驱动程序 必须 始终调用 USBD_QueryUsbCapability ,以确定 USB 驱动程序堆栈和硬件是否支持特定功能。

下表描述了客户端驱动程序可以通过 USBD_QueryUsbCapability 调用查询的特定于 USB 的功能。

功能 GUID 说明
GUID_USB_CAPABILITY_CHAINED_MDLS 如果 USB 驱动程序堆栈支持链式 MDL,则客户端驱动程序可以将传输数据作为引用物理内存中分段缓冲区的 MDL 链提供。 有关详细信息,请参阅 MDL。 链式 MDL 无需分配和复制内存来创建几乎连续的缓冲区,从而使 I/O 传输更高效。 有关详细信息,请参阅 如何发送链接的 MDL
GUID_USB_CAPABILITY_STATIC_STREAMS 如果受支持,客户端驱动程序可以将 I/O 请求发送到批量终结点中的流。

对于静态流查询请求,客户端驱动程序需要提供输出缓冲区 (USHORT) 。 调用完成后,如果支持静态流功能,输出缓冲区将接收主机控制器支持的最大流数。

输出缓冲区值不指示设备中批量终结点支持的最大流数。 若要确定该数字,客户端驱动程序必须检查终结点配套描述符。

Windows 8 中的 USB 驱动程序堆栈最多支持 255 个流。

如果支持静态流,客户端驱动程序可以使用通过选择配置请求获取的管道句柄,将 I/O 请求发送到第一个流 (也称为 默认流) 。 对于终结点中的其他流,客户端驱动程序必须打开这些流并获取它们的管道句柄,以便发送 I/O 请求。 有关打开流的详细信息,请参阅 如何在 USB 批量终结点中打开和关闭静态流

GUID_USB_CAPABILITY_FUNCTION_SUSPEND 此功能确定基础 USB 驱动程序堆栈是否支持 USB 函数挂起和远程 Wake-Up 功能。 如果受支持,驱动程序堆栈可以处理恢复信号 (,以便从 USB 3.0 复合设备中的单个函数远程唤醒) 。 根据该信号,单个函数驱动程序可以退出其函数的低功率状态。

该功能旨在供复合驱动程序使用:作为函数设备对象加载的驱动程序 (复合设备的设备堆栈中的 FDO) 。 默认情况下,Microsoft 提供的 USB 通用父驱动程序 (Usbccgp.sys) 作为 FDO 加载。

如果驱动程序替换 Usbccgp.sys,则驱动程序必须能够请求远程唤醒并从 USB 驱动程序堆栈传播恢复信号。 在实现该逻辑之前,驱动程序必须通过调用 USBD_QueryUsbCapability 来确定 USB 驱动程序堆栈对函数挂起功能的支持。 Windows 8 中的 Usbccgp.sys 实现函数挂起。

有关函数挂起的代码示例和详细信息,请参阅 如何在复合驱动程序中实现函数挂起

GUID_USB_CAPABILITY_SELECTIVE_SUSPEND 确定基础 USB 驱动程序堆栈是否支持选择性挂起。

有关选择性挂起的信息,请参阅 USB 选择性挂起

GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE 确定总线是高速运行还是以更高速度运行。
GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE 确定总线是否以 SuperSpeed 或更高速度运行。
GUID_USB_CAPABILITY_TIME_SYNC 确定控制器上是否支持帧编号和 QPC 关联功能。 
 

示例

代码片段演示如何调用 USBD_QueryUsbCapability 以确定基础 USB 驱动程序堆栈的功能。


/*++

Routine Description:
This helper routine queries the underlying USB driver stack
for specific capabilities. This code snippet assumes that 
USBD handle was retrieved by the client driver in a 
previous call to the USBD_CreateHandle routine.

Parameters:

fdo: Pointer to the device object that is the current top
of the stack as reported by IoAttachDeviceToDeviceStack.

Return Value: VOID
--*/

VOID QueryUsbDriverStackCaps (PDEVICE_OBJECT fdo)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;   
    PDEVICE_EXTENSION deviceExtension;

    deviceExtension = (PDEVICE_EXTENSION)fdo->DeviceExtension;

    if (!deviceExtension->UsbdHandle)
    {
        return;
    }

    // Check if the underlying USB driver stack
    // supports USB 3.0 devices.

    if (!USBD_IsInterfaceVersionSupported(
        deviceExtension->UsbdHandle,                                       
        USBD_INTERFACE_VERSION_602))
    {
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Old USB stack loaded.\n" ));
    }
    else
    {
        // Call USBD_QueryUsbCapability to determine 
        // function suspend support.     
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "New USB stack loaded.\n" ));
        ntStatus = USBD_QueryUsbCapability ( deviceExtension->UsbdHandle,  
            (GUID*)&GUID_USB_CAPABILITY_FUNCTION_SUSPEND,  
            0,  
            NULL,
            NULL);

        if (NT_SUCCESS(ntStatus)) 
        {
            deviceExtension->FunctionSuspendSupported = TRUE;
            KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Function suspend supported.\n" ));
        } 
        else 
        {
            deviceExtension->FunctionSuspendSupported  = FALSE;
            ntStatus = STATUS_SUCCESS;
            KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Function suspend not supported.\n" ));
        }
    }

    // Call USBD_QueryUsbCapability to determine 
    // chained MDL support. 

    ntStatus = USBD_QueryUsbCapability(
        deviceExtension->UsbdHandle,
        (GUID*)&GUID_USB_CAPABILITY_CHAINED_MDLS,
        0,
        NULL,
        NULL);

    if (NT_SUCCESS(ntStatus)) 
    {
        deviceExtension->ChainedMDLSupport = TRUE;
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Chained MDLs supported.\n" ));
    } 
    else 
    {
        deviceExtension->ChainedMDLSupport = FALSE;
        ntStatus = STATUS_SUCCESS;
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Chained MDLs not supported.\n" ));
    }

    // Call USBD_QueryUsbCapability to determine 
    // stream support. 

    ntStatus = USBD_QueryUsbCapability (deviceExtension->UsbdHandle, 
        (GUID*)&GUID_USB_CAPABILITY_STATIC_STREAMS, 
        sizeof(ULONG), 
        (PUCHAR) &deviceExtension->MaxSupportedStreams, 
        NULL);  


    if (!NT_SUCCESS(ntStatus)) 
    {
        deviceExtension->MaxSupportedStreams = 0;
        ntStatus = STATUS_SUCCESS;
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Static streams not supported.\n" ));
    }

    // Call USBD_QueryUsbCapability to determine 
    // selective suspend support. 

    ntStatus = USBD_QueryUsbCapability (deviceExtension->UsbdHandle, 
        (GUID*)&GUID_USB_CAPABILITY_SELECTIVE_SUSPEND, 
        0, 
        NULL, 
        NULL);

    if (!NT_SUCCESS(ntStatus)) 
    {
        ntStatus = STATUS_SUCCESS;
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Selective suspend not supported.\n" ));
    }
    else
    {
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Selective suspend supported.\n" ));
    }

    // Call USBD_QueryUsbCapability to determine 
    // device speed. 
    ntStatus = USBD_QueryUsbCapability (deviceExtension->UsbdHandle, 
        (GUID*)&GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE, 
        0, 
        NULL, 
        NULL);

    if (!NT_SUCCESS(ntStatus)) 
    {
        ntStatus = STATUS_SUCCESS;
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "The device is operating at full speed or lower.\n The device can operate at high speed or higher." ));
    }
    else
    {
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "The device is operating at high speed or higher.\n" ));
    }

    // Call USBD_QueryUsbCapability to determine 
    // device speed. 
    ntStatus = USBD_QueryUsbCapability (deviceExtension->UsbdHandle, 
        (GUID*)&GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE, 
        0, 
        NULL, 
        NULL);

    if (!NT_SUCCESS(ntStatus)) 
    {
        ntStatus = STATUS_SUCCESS;
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "The device is operating at high speed or lower.\n The device can operate at Superspeed or higher." ));
    }
    else
    {
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "The device is operating at SuperSpeed or higher.\n" ));
    }

    return;

}

要求

要求
最低受支持的客户端 Windows 8需要 WDK。 面向 Windows Vista 和更高版本的 Windows 操作系统。
目标平台 桌面
标头 usbdlib.h (包括 Usbdlib.h)
Library Usbdex.lib
IRQL PASSIVE_LEVEL

另请参阅

USB device driver programming reference(USB 设备驱动程序编程参考)