Querying Device Capabilities
This document provides an overview of how to query the capabilities of a Plug and Play (PNP) device in Windows. Understanding a device's capabilities is crucial for drivers to interact with it correctly and efficiently.
Overview of Device Capabilities
Device capabilities describe what a device can do, how it operates, and what resources it requires. These capabilities are reported by the hardware and interpreted by the operating system and its drivers. Key aspects of device capabilities include:
- Resource Requirements: Such as I/O ports, memory ranges, and interrupt requests (IRQs).
- Power Management Features: Including support for various sleep states (D0, D1, D2, D3).
- Device Type and Class: Identifying the general category of the device (e.g., display adapter, network adapter).
- Interfacing Methods: How the device communicates with the system (e.g., I2C, SPI, PCI).
- Direct Memory Access (DMA): Whether the device supports DMA transfers.
Methods for Querying Capabilities
Windows provides several mechanisms for drivers and applications to query device capabilities:
1. Using IRPs (I/O Request Packets)
Kernel-mode drivers typically use IRPs to communicate with the Plug and Play Manager and other system components. The primary IRP for querying device capabilities is IRP_MJ_PNP with the PnP subfunction code IRP_MN_QUERY_CAPABILITIES.
When a driver receives an IRP_MN_QUERY_CAPABILITIES request, it must populate a PNP_CAPABILITIES structure with information about the device.
// Example structure of PNP_CAPABILITIES (simplified)
typedef struct _PNP_CAPABILITIES {
ULONG Size;
BOOLEAN Removable;
BOOLEAN Dockable;
BOOLEAN Ejectable;
BOOLEAN HardwareDisabled;
// ... other capability flags
} PNP_CAPABILITIES, *PPNP_CAPABILITIES;
// When handling IRP_MN_QUERY_CAPABILITIES
NTSTATUS
MyPnpDispatch(
_Inout_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp
)
{
PIO_STACK_LOCATION irpSp;
PPNP_CAPABILITIES capabilities;
NTSTATUS status;
irpSp = IoGetCurrentIrpStackLocation(Irp);
switch (irpSp->MinorFunction) {
case IRP_MN_QUERY_CAPABILITIES:
capabilities = (PPNP_CAPABILITIES)irpSp->Parameters.QueryCapabilities.Capabilities;
capabilities->Size = sizeof(PNP_CAPABILITIES);
capabilities->Removable = TRUE; // Example: This device is removable
capabilities->Dockable = FALSE;
capabilities->Ejectable = TRUE;
capabilities->HardwareDisabled = FALSE;
// Populate other fields as necessary
status = STATUS_SUCCESS;
break;
// ... other PNP functions
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
// Pass the IRP down the stack or complete it
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
2. Using SetupAPI Functions (User Mode)
Applications and user-mode drivers can use the SetupAPI (setupapi.dll) to query device information, including capabilities. Functions like SetupDiGetDeviceRegistryProperty can retrieve various properties, some of which relate to capabilities.
Relevant properties might include:
SPDRP_CAPABILITIES: A bitmask indicating general device capabilities.SPDRP_REMOVAL_POLICY: Defines how a device should be handled during removal.
// Example using SetupAPI in C++
#include <windows.h>
#include <setupapi.h>
#pragma comment(lib, "Setupapi.lib")
// ... (obtain device information set and device instance handle)
DWORD capabilities = 0;
if (SetupDiGetDeviceRegistryProperty(
hDeviceInfoSet,
&DeviceInfoData,
SPDRP_CAPABILITIES,
NULL,
(PBYTE)&capabilities,
sizeof(capabilities),
NULL))
{
// Process the capabilities DWORD
if (capabilities & CM_DEVCAP_REMOVABLE) {
// Device is removable
}
// ... check other CM_DEVCAP_ flags
}
The PNP_CAPABILITIES Structure
The PNP_CAPABILITIES structure (used in kernel mode) contains flags that describe the device's inherent properties:
| Member | Description |
|---|---|
Size |
The size of the PNP_CAPABILITIES structure. |
Removable |
Indicates if the device can be removed from the system while the system is running. |
Dockable |
Indicates if the device is part of a docking station. |
Ejectable |
Indicates if the device can be ejected by the user (e.g., via a physical button or software command). |
HardwareDisabled |
Indicates if the device is currently disabled by hardware. |
NonDynamicValue |
A placeholder for future expansion. |
SurpriseRemovalUnsupported |
Indicates that the device does not support surprise removal gracefully. |
Note on Surprise Removal
If SurpriseRemovalUnsupported is set, drivers should prepare for the device being removed without prior notification. This typically involves flushing any pending I/O operations and cleaning up resources.
Querying Resource Requirements
Beyond general capabilities, drivers often need to know the specific hardware resources a device requires. This is typically queried using IRP_MN_QUERY_RESOURCE_REQUIREMENTS for raw resource needs or IRP_MN_QUERY_RESOURCES for assigned resources. The Plug and Play Manager assigns resources after consulting these requirements.
Power Management Capabilities
A device's power management capabilities are also critical. These can be queried through specific PnP IRPs related to power management, such as IRP_MN_QUERY_POWER, and by examining device properties that indicate support for different power states (e.g., D0, D1, D2, D3).
Important Consideration
Always ensure your driver correctly reports and handles device capabilities. Failure to do so can lead to device malfunctions, system instability, and incorrect resource allocation.