Handling IRP_MN_SET_POWER for Device Power States
A device set-power IRP requests a change of state for a single device and is sent to all 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 power-down IRPs as they travel down the stack. For power-up IRPs, drivers set IoCompletion routines as the IRPs travel down the stack, and then handle the IRPs in the IoCompletion routines as the IRPs travel back up the stack. The drivers in a typical device stack handle a device set-power IRP as follows:
Most filter drivers should simply call IoMarkIrpPending, pass the IRP to the next-lower driver (see Passing Power IRPs), and return STATUS_PENDING from the DispatchPower routine. 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 calls IoMarkIrpPending, 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 if necessary, 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 changes device power if it is capable of doing so and then calls PoSetPowerState to notify the power manager of the new device power state. In Windows Server 2003, Windows XP, and Windows 2000 only, the driver must also call PoStartNextPowerIrp to start the next power IRP after it sets the power state. The driver 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 requested power state, each function or filter driver must pass the IRP down to the next-lower driver. Every set-power IRP must travel all the way down the device stack to the bus driver, which completes it.
Function and filter drivers that are located above a bus driver must not fail a device set power IRP. The bus driver can fail a device power-up IRP if the device is removed or in the process of being removed.
Each driver (function, filter, and bus driver) in a driver stack must call PoSetPowerState to inform the power manager of a change in the power state of its corresponding device object.
Like other driver tasks associated with device power-up and power-down, the call to PoSetPowerState must occur after the device powers on (if the new state is D0) or before the device powers off (if the new state is any other state).
Each driver should keep track of the power state of its device. The power manager does not supply this information to drivers.
While handling an IRP_MN_SET_POWER request for a device power state, 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.
To ensure the highest level of system performance, especially for multimedia applications, a driver should perform time-consuming operations at an interrupt request level (IRQL) equal to PASSIVE_LEVEL. To perform operations at IRQL= PASSIVE_LEVEL, a driver can use a dedicated thread or a system worker thread. For guidelines on optimizing driver performance for multimedia platforms, see the Device-Driver Performance Considerations for Multimedia Platforms website.
The exact steps a driver must take to handle a power IRP depend upon whether the device is powering up or down, as described in the following sections: