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 状态代码。
可能的值包括但不限于下表中列出的状态代码。
| 返回代码 | 描述 |
|---|---|
|
请求成功,并且支持指定的功能。 |
|
调用方传递的参数值无效。
|
|
基础 USB 驱动程序堆栈不支持指定的功能。 |
|
主机控制器硬件或 USB 驱动程序堆栈不支持指定的功能。 |
言论
Windows 8 包含支持 USB 3.0 设备的新 USB 驱动程序堆栈。 新的 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) |
| 库 | Usbdex.lib |
| IRQL | PASSIVE_LEVEL |