The PnP manager sends this IRP to get the capabilities of a device, such as whether the device can be locked or ejected.
Function and filter drivers can handle this request if they alter the capabilities supported by the bus driver. Bus drivers must handle this request for their child devices.
The PnP manager sends this IRP to the bus driver for a device immediately after the device is enumerated. The PnP manager sends this IRP again after all the drivers for a device have started the device. A driver can send this IRP to get the capabilities for a device.
The PnP manager and drivers send this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.
Parameters.DeviceCapabilities.Capabilities points to the DEVICE_CAPABILITIES structure that reflects any modifications made by the drivers that handle the IRP.
I/O Status Block
A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_UNSUCCESSFUL.
If a function or filter driver does not handle this IRP, it calls IoSkipCurrentIrpStackLocation and passes the IRP down to the next driver. Such a driver must not modify Irp->IoStatus.Status and must not complete the IRP.
A bus driver sets Irp->IoStatus.Status and completes the IRP.
When a device is enumerated, but before the function and filter drivers are loaded for the device, the PnP manager sends an IRP_MN_QUERY_CAPABILITIES request to the parent bus driver for the device. The bus driver must set any relevant values in the DEVICE_CAPABILITIES structure and return it to the PnP manager.
After the device stack is built and drivers have started the device, the PnP manager sends this IRP again to be handled first by the driver at the top of the device stack and then by each lower driver in the stack. Function and filter drivers can set an IoCompletion routine and handle this IRP on its way back up the device stack.
Drivers should add capabilities before they pass the IRP to the next lower driver.
Drivers should remove capabilities after all lower drivers have finished with the IRP. A driver does not typically remove capabilities that have been set by other drivers, but it might do so if it has special information about the capabilities of the device in a certain configuration. See Plug and Play for information about postponing IRP processing until lower drivers have finished.
After a device is enumerated and its drivers are loaded, its capabilities should not change. A device's capabilities might change if the device is removed and re-enumerated.
When handling an IRP_MN_QUERY_CAPABILITIES IRP, the driver that is the power policy manager for the device should set an IoCompletion routine and copy the device power capabilities, such as the S-to-D power state mappings, on the IRP's way back up the device stack. To determine the power capabilities of a child device, the parent bus driver creates another query-capabilities IRP and sends the IRP to its parent driver. See Reporting Device Power Capabilities for more information.
If a driver handles this IRP, it should check the DEVICE_CAPABILITIES Version value. If that value is not a version that the driver supports, the driver should fail the IRP. If the version is supported, the driver should check the Size field. A driver should set only those fields that are within the bounds of the capabilities structure that it received as input.
Drivers that handle this IRP can set some DEVICE_CAPABILITIES fields but must not set the Size and Version fields. These fields are only set by the component that sent the IRP.
Sending This IRP
A bus driver sends this IRP to the parent device stack when it handles an IRP_MN_QUERY_CAPABILITIES request for one of its child devices. Also, a driver might send this IRP to get the device capabilities for one of its devices. A single driver in the stack has only part of the capabilities information for the device; sending an IRP to the device stack enables it to gather the full picture, including modifications by any filter drivers, and so forth.
See Handling IRPs for information about sending IRPs. The following steps apply specifically to this IRP:
Allocate a DEVICE_CAPABILITIES structure from paged pool, and initialize it to zeros by calling RtlZeroMemory. Initialize the Size to sizeof(DEVICE_CAPABILITIES), the Version to 1, and Address and UINumber to -1.
Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_QUERY_CAPABILITIES, and set Parameters.DeviceCapabilities to a pointer to the allocated DEVICE_CAPABILITIES structure.
Initialize IoStatus.Status to STATUS_NOT_SUPPORTED.
Deallocate the IRP and the DEVICE_CAPABILITIES structure when they are no longer needed.