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;

Device Power Policy Owner

In most device stacks, there is one driver that knows if the device is being used and its power state. This driver is deemed the device power policy owner. There is nothing to stop more than one driver trying to set power policy. In most cases, the first function driver for a device is the power policy owner. However, the bus driver may well play an important part in power management, or even be the power policy owner.

The device power policy owner should call PoSetPowerState to set the current device power state. This device power state is stored for a device by the Power Manager. However, there is no call to retrieve the current device power state, so you must keep a copy of this value.

The Wdm2 driver defines the following two extra fields in its device extension to support Power Management.

DEVICE_POWER_STATE PowerState; // Our device power state

PULONG PowerIdleCounter; // Device idle counter

The AddDevice routine initializes these variables as follows. PoSetPowerState can only be used by drivers to set the device power state. Do not try to set the system power state.

dx->PowerState = PowerDeviceD3;

dx->PowerIdleCounter = NULL;

POWER_STATE NewState;

NewState.DeviceState = dx->PowerState;

PoSetPowerState(fdo, DevicePowerState, NewState);

An AddDevice routine can also set some extra bits in the FDO Flags. If DO_POWER_INRUSH is set, this device needs an inrush of power when it is powered up. Devices with this bit set are powered up one at a time. If the DO_POWER_PAGABLE flag bit is set, the Power handling routines are called at PASSIVE_LEVEL IRQL. Otherwise, they are called at DISPATCH_LEVEL IRQL. Inrush Power IRPs are sent at DISPATCH_LEVEL, so the power routines for these devices must not be pageable.

The device power policy owner must process Query and Set Power IRPs using the technique described previously. The following Wdm2 example shows how to do this in detail.

It is recommended that a device is fully powered up by the time the Plug and Play StartDevice IRP has completed. As you will get only the full list of resources with this Start Device IRP, you will have to power up the device once the resources have been found and allocated. There might well be no need to power down a device during resource reassignment.

You may decide that the device can be powered off when it has been idle for a while. The easiest way to do this is to call the PoRegisterDeviceForIdleDetection function. After a time-out, the Power Manager sends a Set device power IRP to power down the device. Alternatively, you can generate a similar IRP yourself whenever you deem it appropriate. To avoid an idle time-out, you must keep resetting an idle counter using PoSetDeviceBusy every time an I/O operation takes place.

The following line at the end of AddDevice shows how to register for idle notification. The two ULONG parameters are the time-outs in seconds. The first applies when the system is trying to conserve power. The second applies when best performance is the goal. The final parameter to PoRegisterDeviceForIdleDetection is the device state that must be set when a device powers down. Wdm2 powers down to device state D3. Call PoRegisterDeviceForIdleDetection with zeroes for the time-outs to disable idle notification.

dx->PowerIdleCounter = PoRegisterDeviceForIdleDetection(pdo, 30, 60, PowerDeviceD3);

The following code snippet shows how PoSetDeviceBusy is used to reset the idle counter at the beginning of each I/O operation.

if (dx->PowerIdleCounter) PoSetDeviceBusy(dx->PowerIdleCounter);

At the beginning of every I/O operation, you must check to see if the device is powered up. If it is not, most drivers will simply power up the device before starting the request. An alternative strategy is to queue the IRP until the device powers up at some other time.

Make sure that you do not accidentally power down a device during a lengthy I/O operation.

Handling Set Power IRPs

The parameters on the stack of a Set Power IRP indicate which system or device power state is being set.

If Parameters.Power.Type is SystemPowerState, Parameters.Power.State.SystemState is the desired system state. If Parameters.Power.Type is DevicePowerState, Parameters.Power.State.DeviceState is the desired device state. The Parameters.Power.ShutdownType field gives more information about system Shutdown messages. A final parameter, Parameters.Power.SystemContext, is not currently used.

Listing 10.2 shows the main Wdm2 handler for all Power IRPs, Wdm2Power. If this is a Set Power IRP, PowerSetPower is called. Other Power IRPs are passed to DefaultPowerHandler, which simply hands them down to the lower drivers in the same way as Wdm1. All Power IRPs are completed with an error status if the device is not in the started PnP state.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×