Listing 10.2 Basic Wdm2 power handling
NTSTATUS Wdm2Power(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
PWDM2_DEVICE_EXTENSION dx = (PWDM2_DEVICE_EXTENSI0N)fdo->DeviceExtension;
if (dx->IODisabled) return CompleteIrp(Irp, STATUS_DEVICE_NOT_CONNECTED, 0);
if (!LockDevice(dx)) return CompleteIrp(Irp, STATUS_DELETE_PENDING, 0);
NTSTATUS status = STATUS_SUCCESS;
DebugPrint('Power %I',Irp);
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG MinorFunction = IrpStack->MinorFunction;
if (MinorFunction==IRP_MN_SET_POWER) status = PowerSetPower(dx,Irp);
else status = DefaultPowerHandler(dx,Irp);
UnlockDevice(dx);
return status;
}
NTSTATUS DefaultPowerHandler(IN PWDM2_DEVICE_EXTENSION dx, IN PIRP Irp) {
DebugPrintMsg('DefaultPowerHandler');
// Just pass to lower driver
PoStartNextPowerIrp(Irp);
IoSkipCurrentlrpStackLocation(Irp);
return PoCallDriver(dx->NextStackDevice, Irp);
}
Listing 10.3 shows the
Listing 10.3 PowerSetPower routine
NTSTATUS PowerSetPower(IN PWDM2_DEVICE_EXTENSION dx, IN PIRP Irp) {
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_IOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
POWER_STATE_TYPE PowerType = IrpStack->Parameters.Power.Type;
POWER_STATE PowerState = IrpStack->Parameters.Power.State;
////////////////////////////////////////////////////////////////////
// Set System Power
if (PowerType==SystemPowerState) {
DEVICE_POWER_STATE DesiredDevicePowerState = (PowerState.SystemState<=PowerSystemWorking ? PowerDeviceD0 : PowerDeviceD3);
if (DesiredDevicePowerState<dx->PowerState) {
// This system state means we have to increase device power
DebugPrint('System state %d. Increase device power to %d', PowerState.SystemState, DesiredDevicePowerState);
// Process on way up stack…
PoStartNextPowerIrp(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, OnCompleteIncreaseSystemPower, NULL, TRUE, TRUE, TRUE);
return PoCallDriver(dx->NextStackDevice, Irp);
} else if(DesiredDevicePowerState>dx->PowerState) {
// This system state means we have to decrease device power
DebugPrint('System state %d. Decrease device power to %d',
PowerState.SystemState, DesiredDevicePowerState);
// Send power down request to device
status = SendDeviceSetPower(dx, DesiredDevicePowerState);
if (!NT_SUCCESS(status)) {
PoStartNextPowerIrp(Irp);
return CompleteIrp(Irp, status, 0);
}
}
}
////////////////////////////////////////////////////////////////////
// Set Device Power
else if (PowerType==DevicePowerState) {
DEVICE_POWER_STATE DesiredDevicePowerState = PowerState.DeviceState;
if (DesiredDevicePowerState<dx->PowerState) {
// Increase device power state
DebugPrint('Increase device power to %d', DesiredDevicePowerState);
// Process on way up stack…
PoStartNextPowerIrp(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, OnCompleteIncreaseDevicePower, NULL,TRUE, TRUE, TRUE);
return PoCallDriver(dx->NextStackDevice, Irp);
} else if (DesiredDevicePowerState>dx->PowerState) {
// Decrease device power state
DebugPrint('Decrease device power to %d', DesiredDevicePowerState);
// Set power state
SetPowerState(dx,PawerState.DeviceState);
}
}
////////////////////////////////////////////////////////////////////
// Unrecognised Set Power
#if DBG
else DebugPrint('Power: unrecognised power type %d',PowerType);
#endif
// Finally pass to lower drivers return DefaultPowerHandler(dx, Irp);
}
When a new system state is being set, the first task is determining to which device power state this corresponds. As mentioned previously, in Wdm2 the fully on D0 device state is only used for the fully on SO system power state. For all other system power states, the fully off D3 device state is used.
If the device needs to be powered up, the situation depicted in Figure 10.3 applies. The Set System Power IRP handler can start the device only after the lower drivers have processed the request.
Listing 10.4 shows how
If the device needs to be powered down, as per Figure 10.2, PowerSetPower calls
Listing 10.4 OnCompleteIncreaseSystemPower routine
NTSTATUS OnCompleteIncreaseSystemPower(IN PDEVICE_OBJECT fdo, IN PIRP Irp, IN PVOID context) {