Книга: Writing Windows WDM Device Drivers

Power IRPs

Power IRPs

A driver's Power Management routines revolve around the Power IRP, IRP_MJ_POWER, by both handling it and generating it when necessary. There are four minor function code variants of the Power IRP shown in Table 10.3.

Table 10.3 IRP_MN_POWER minor function codes

Minor function code Description
IRP_MN_SET_POWER Set system or device power state
IRP_MN_QUERY_POWER Ask if a system or device state change is OK
IRP_MN_WAIT_WAKE Wake computer in response to an external event
IRP_MN_POWER_SEQUENCE Send this IRP to determine whether your device actuallyentered a specific power state

The Power Manager maintains a separate internal queue of Power IRPs. This ensures that there is only one Set System Power IRP being processed in the system. It also ensures that there is only one Set Device Power IRP running for each device. These rules ensure that power transitions are handled smoothly. As each device is powered up, it may require an inrush of energy. Handling Power IRPs one at a time ensures that the peak power required is kept as low as possible.

As the Power Manager has its own queue of IRPs, do not use the standard I/O Manager routines when handling IRPs. Use PoCallDriver instead of IoCallDriver to call the next driver down the stack.

You must tell the Power Manager when you have finished processing a power IRP so that it can start the next. If you are simply passing an IRP down the stack (with no completion routine) then you should call the PoStartNextPowerIrp function before you skip or copy the current IRP stack location. If you use a completion routine, it must also usually call PoStartNextPowerIrp. Full examples of these calls are given later.

Processing Power IRPs

A Query Power IRP request is sent to see if a state change is acceptable to all the drivers in the device stack. A Set Power IRP is then issued to actually make the change.

You can send yourself a Set Device Power State IRP at any time. However, only the Power Manager can send Set System Power State IRPs. To process a Set System Power State IRP, you must send yourself a Set Device Power State IRP. That's right — you must ask for a Power IRP to be sent to the top of your device stack.

Handling Device Power IRPs

Handling a Set Device Power State is relatively straightforward. You must power down your device before all the lower drivers. Conversely, power your device up after all the lower drivers have powered up. This means setting a completion routine and doing the power up there.

Handling System Power IRPs

Handling a Set System Power State is a different kettle of fish. If you receive a Set System Power IRP, you must first determine the equivalent device power state. The Wdm2 driver is put in the fully on device state D0 for the fully on system state S0. For all other system states, the Wdm2 device state is fully off, D3.

If the current device state is not the same as the required device state, you must act to change it. As before, powering down requires that you change the device state before you pass the Set System Power State down to the lower drivers. Power up after all the lower drivers have had their say.

You must change device power state by issuing a Set Device Power State IRP to yourself. You must then wait for this IRP to complete. You can then continue processing the Set system state IRP.

Same System Power

Suppose you receive a Set System Power State IRP. You must work out the corresponding device power state. If your device is already at this power level, then all you need to do is pass the IRP to the lower drivers.

System Powering Down

If you decide that your device needs to power down, then you must send yourself a Set Device Power IRP before you pass down the system IRP. Figure 10.2 illustrates this scenario. It assumes that the first Query Set System Power State IRP has completed OK, at (1).

In the figure, the Set System State IRP handler decides that it must power its device down at (2). It sends a Set Device State IRP to itself, and sets a completion routine so that it knows when this second IRP has been completed.

In due course, your driver will receive the Set Device State IRP (that you sent yourself) at (3). Your driver will decide again that it must power down. It does this at (4) and then sends the IRP down to the lower drivers at (5).

When the Set Device State IRP has been processed by all the lower drivers, the completion routine is called at (6). This signals to the original IRP handler that it can continue, at © again. All this has to do is pass the IRP down to the lower drivers at (7).

Figure 10.2 Power down system processing


System Powering Up

In contrast, Figure 10.3 shows what might happen when your device has to power up to get to the required new system power state. First, a Query Power IRP is sent at (1) asking if a new system state is OK. Then a Set Power IRP is issued for the system power state. The driver determines that it must power up its device. It sets a completion routine and passes the IRP to the lower drivers at (2).

The completion routine for the Set System State sends itself a Set Device State Power IRP at (3), setting a completion routine. When this IRP gets to your driver, it again works out that it must power up. It passes the IRP to the lower drivers at (4) and sets another completion routine. When this completion routine runs at (5), the driver can finally power its device up in whatever way is appropriate at (6).

The completion routine at (7) runs. The original Set System State Power IRPcompletion routine at (3) eventually continues its run. It completes the first IRP.

This example appears complicated, as there are three different IRP completion routines involved. However, the full example given later should make the process clear. The original Set System State IRP needs a completion routine at (3) so that the driver knows when the IRP has been processed by the rest of the stack. This completion routine must send a Set Device State IRP to itself. It needs a completion routine at (7) so that it knows when this IRP has completed its rites of passage. Finally, when the driver processes the Set Device State IRP, it needs a completion routine at (5) so that it knows when the lower drivers have finished processing this IRP.

Figure 10.3 Power up system processing


Not Processing Power IRPs

Some drivers like Wdm1 (and in fact, Wdm2) can happily ignore all Power IRPs. All they have to do is pass all Power IRPs down the stack. Wdm1's Wdm1 Power dispatch routine shown in Listing 10.1 does just this. Note the use of PoCallDriver rather than IoCallDriver. If you do not process Power IRPs, please include a default power handler like Wdm1 Power so that these IRPs reach lower drivers.

Drivers for removable devices should check to see if its media is present; if not, it should call PoStartNextPowerIrp and complete the Power IRP straightaway with a status of STATUS_DELETE_PENDING.

Listing 10.1 Passing on all Power IRPs

NTSTATUS Wdm1Power(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
 DebugPrint("Power %I", Irp);
 PWDM1_DEVICE_EXTENSION dx = (PWDM1_DEVICE_EXTENSION)fdo->DeviceExtension;
 // Just pass to lower driver
 PoStartNextPowerIrp(Irp);
 IoSkipCurrentIrpStackLocation(Irp);
 return PoCallDriver(dx->NextStackDevice, Irp);
}

Noting Device Power State Changes

Suppose a function driver does not handle Power IRPs, but its bus driver does. In this case, the function driver might want to know when its device is powered down and take some appropriate action. Unfortunately, there is no simple call to discover the current device power state. Instead, it must remember the last device power state from a Set Power IRP.

The Power IRP handler can easily be enhanced to note any changes of power state if the minor function code is IRP_MN_SET_POWER. The IRP stack Parameters.Power.Type field is either SystemPowerState or DevicePowerState. The Parameters.Power.State field gives the system or device power state.

The following code snippet shows how to check for a Set Device Power IRP and store the new device power state in a DEVICE_POWER_STATE PowerState field in the device extension.

PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
POWER_STATE_TYPE PowerType = IrpStack->Parameters.Power.Type;
POWER_STATE PowerState = IrpStack->Parameters.Power.State;
if (IrpStack->MinorFunction==IRP_MN_SET_POWER && PowerType==DevicePowerState) dx->PowerState = PowerState.DeviceState;

Оглавление книги


Генерация: 1.187. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз