Handling IRP_MN_QUERY_POWER for Device Power States
A device query-power IRP queries about a change of state for a single device and is sent to all of the drivers in the stack for the device. Such an IRP specifies DevicePowerState in the Power.Type member of the I/O stack location.
Drivers handle query-power IRPs as they travel down the stack.
A function or filter driver can fail an IRP_MN_QUERY_POWER request if any of the following is true:
The device is enabled for wake-up and the requested power state is below the state from which the device can wake the system. For example, a device that can wake the system from D2 but not from D3 would fail a query for D3 but succeed a query for D2.
Entering the requested state would force the driver to abandon an operation that would lose data, such as an open modem connection. A driver rarely will fail a query for this reason; under most circumstances, the application handles such cases.
To fail an IRP_MN_QUERY_POWER request, a driver takes the following steps:
Call PoStartNextPowerIrp to indicate that the driver is prepared to handle the next power IRP. (Windows Server 2003, Windows XP, and Windows 2000 only.)
Set Irp->IoStatus.Status to a failure status and call IoCompleteRequest, specifying IO_NO_INCREMENT. The driver does not pass the IRP further down the device stack.
Return an error status from its DispatchPower routine.
If the driver succeeds the query-power IRP, it must not start any operations or take any other action that would prevent its successful completion of a subsequent IRP_MN_SET_POWER request to the queried power state.
A driver that succeeds the IRP must prepare for a set-power IRP for the queried state and pass down the query IRP, as follows:
Finish any outstanding I/O operations.
Queue incoming I/O requests.
Avoid starting any other new activities that would interfere with a transition to the specified power state. However, the driver should not save device context or take other steps toward shutdown.
Call IoCopyCurrentIrpStackLocationToNext to set the IRP stack location for the next-lower driver.
Set an IoCompletion routine. In the IoCompletion routine, call PoStartNextPowerIrp (Windows Server 2003, Windows XP, and Windows 2000 only) to indicate the driver's readiness to handle the next power IRP.
Call IoCallDriver (in Windows 7 and Windows Vista) or PoCallDriver (in Windows Server 2003, Windows XP, and Windows 2000) to pass the query IRP to the next-lower driver. Do not complete the IRP.
Return STATUS_PENDING. The driver must not change the value at Irp->IoStatus.Status.
When the query-power IRP reaches the bus driver, the bus driver calls PoStartNextPowerIrp (Windows Server 2003, Windows XP, and Windows 2000 only) and sets Irp->IoStatus.Status to STATUS_SUCCESS if the driver can change to the specified power state or sets a failure status if it cannot. The bus driver then calls IoCompleteRequest, specifying IO_NO_INCREMENT.
The drivers in a typical device stack handle a device query-power IRP as follows:
Most filter drivers should simply pass the IRP to the next-lower driver (see Passing Power IRPs) and return STATUS_PENDING. Some filter drivers, however, might first need to perform device-specific tasks, such as queuing incoming IRPs or saving device power state.
A function driver performs device-specific tasks (such as, completing pending I/O requests, queuing incoming I/O requests, saving device context, or changing device power), sets an IoCompletion routine, and passes the device power IRP to the next-lower driver (see Passing Power IRPs). It returns STATUS_PENDING from its DispatchPower routine.
The bus driver calls PoStartNextPowerIrp (Windows Server 2003, Windows XP, and Windows 2000 only) to start the next power IRP. It then completes the IRP, specifying IO_NO_INCREMENT. If the driver cannot complete the IRP immediately, it calls IoMarkIrpPending, returns STATUS_PENDING from its DispatchPower routine, and completes the IRP later.
Even if the target device is already in the queried power state, each function or filter driver must queue I/O and pass the IRP down to the next-lower driver. The IRP must travel all the way down the device stack to the bus driver, which completes it.
While handling an IRP_MN_QUERY_POWER request, a driver should return from the DispatchPower routine as quickly as possible. A driver must not wait in its DispatchPower routine for a kernel event signaled by code that handles the same IRP. Because power IRPs are synchronized throughout the system, a deadlock might occur.