Handling a System Query-Power IRP in a Device Power Policy Owner

When a device power policy owner receives an IRP_MN_QUERY_POWER for a system power state, it responds by passing down the query and, in an IoCompletion routine, sending an IRP_MN_QUERY_POWER for a device power state. When all drivers in the stack have completed the device query, the device power policy owner completes the system query.

A device power policy owner should take the following steps in its DispatchPower routine to respond to a system query:

  1. Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the power IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, beginning with Windows Vista, the driver should call IoCompleteRequest to complete the IRP and return the failure status. In Windows Server 2003, Windows XP, and Windows 2000, the driver should call PoStartNextPowerIrp, call IoCompleteRequest to complete the IRP, and return the failure status.

  2. Ensure that the driver can support the queried system power state, as described in Failing a System Query-Power IRP in a Filter or Function Driver. If not, complete the IRP with a failure status as described in that section.

    However, a driver must not fail a query for S4 (PowerSystemHibernate) if its device is enabled for wake-up but it cannot wake the system from the hibernate state. In this case, the power policy owner for the driver (which sent the IRP_MN_WAIT_WAKE) must cancel the wait/wake IRP and succeed the system query. For more information, see Canceling a Wait/Wake IRP.

  3. If the driver can support the queried system power state, call IoMarkIrpPending.

  4. Set up the IRP stack location for the next-lower driver by calling IoCopyCurrentIrpStackLocationToNext.

  5. Set an IoCompletion routine in the system query power IRP.

  6. Call IoCallDriver (in Windows 7 and Windows Vista) or PoCallDriver (in Windows Server 2003, Windows XP, and Windows 2000), to pass the IRP to the next-lower driver.

  7. Return STATUS_PENDING.

The IoCompletion routine should do the following:

  1. Check Irp->IoStatus.Status to ensure that lower drivers have completed the IRP successfully. If a lower driver has specified a non-success NTSTATUS value, the IoCompletion routine should return the NTSTATUS value.

  2. If lower drivers have successfully completed the IRP, call PoRequestPowerIrp to send a device query-power IRP for a device power state that is valid for the queried system power state. If necessary, consult the DEVICE_STATE array in the DEVICE_CAPABILITIES structure to determine which device power states are valid for the queried system power state.

  3. Specify a callback routine (CompletionFunction parameter) in the call to PoRequestPowerIrp and pass the system IRP in the Context area.

  4. Return STATUS_MORE_PROCESSING_REQUIRED so that the driver can finish processing the system query IRP in the callback routine.

After the IRP has been completed and all IoCompletion routines set during IRP processing have been run, the power manager, through the I/O manager, calls the power policy manager's callback routine (the CompletionFunction parameter to PoRequestPowerIrp). The callback routine, in turn, must do the following:

  1. Call PoStartNextPowerIrp to start the next power IRP. (Windows Server 2003, Windows XP, and Windows 2000 only.)

  2. Complete the system query-power IRP (call IoCompleteRequest) with the status returned for the device query-power IRP.

  3. Call IoReleaseRemoveLock to free the previously acquired lock.

Remember that the device power policy owner not only sends the device query but also must handle it on its way down the device stack. For more information, see Handling IRP_MN_QUERY_POWER for Device Power States.