// Remember new state
dx->PowerState = NewDevicePowerState;
POWER_STATE NewState;
NewState.DeviceState = NewDevicePowerState;
PoSetPowerState(dx->fdo, DevicePowerState, NewState);
}
Dispatch Routine Power Handling
Each Wdm2 I/O request dispatch routine must check that the Wdm2 device is powered up. Listing 10.8 shows how Wdm2Write calls
Listing 10.8 Dispatch routine power handling
NTSTATUS Wdm2Write(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
// …
NTSTATUS status = PowerUpDevice(fdo);
if (!NT_SUCCESS(status)) return CompleteIrp(Irp, status, 0);
// …
}
NTSTATUS PowerUpDevice(IN PDEVICE_OBJECT fdo) {
PWDM2_DEVICE_EXTENSION dx = (PWDH2_DEVICE_EXTENSION)fdo->DeviceExtension;
// If need be, increase power
if (dx->PowerState>PowerDeviceD0) {
NTSTATUS status = SendDeviceSetPower(dx, PowerDeviceD0);
if (!NT_SUCCESS(status)) return status;
}
// Zero our idle counter
if (dx->PowerIdleCounter) PoSetDeviceBusy(dx->PowerIdleCounter);
return STATUS_SUCCESS;
}
Testing Wdm2 Power Capabilities
You can investigate some of Wdm2's power capabilities by inspecting the checked build DebugPrint output using the DebugPrint Monitor. Make sure that you have installed the DebugPrint driver and the checked build of the Wdm2 driver.
Under W2000, the idle detection process can be seen working. After 60 seconds on my AC powered desktop system, the Power Manager sends a Set device Power IRP to power down the device to D3. If you then run the Wdm2Test Win32 application, the first read or write powers the Wdm2 device back up to D0.
On the same computer running Windows 98, no idle Set device Power IRPs were seen. This must be another manifestation of the bug described earlier. I changed the code so that Wdm2 started in a powered off state. When Wdm2Test was run, the Set device Power IRP (to power the device up) completed successfully, but the driver was not sent the Power IRP. This is why
I cannot explain why Set Power IRPs are not received by the Wdm2 driver in Windows 98. Perhaps the idle detection process is working, but the Set device IRP is simply not seen by the driver.
If your system can sleep or hibernate then use the
Device Capabilities
Another piece of the Power Management puzzle is the IRP_MN_QUERY_CAPABILITIES Plug and Play IRP minor function code. The bus driver usually fills in a DEVICE_CAPABILITIES structure. Several of these fields relate to Power Management. Function or filter drivers can inspect or modify the values set by the bus driver.
Listing 10.9 shows how
The
Listing 10.9 PnpQueryCapabilitiesHandler routine
#define SetMostPoweredState(SystemState, OurDeviceState)
dps = deviceCapabilities->DeviceState[SystemState];
if (dps==PowerDeviceUnspecified || dps>OurDeviceState)
deviceCapabilities->DeviceState[SystemState] = OurDeviceState
NTSTATUS PnpQueryCapabilitiesHandler(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
NTSTATUS status = ForwardIrpAndWait(fdo, Irp);
if (NT_SUCCESS(status)) {
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_CAPABILITIES deviceCapabilities;
deviceCapabilities = IrpStack-Parameters->DeviceCapabilities.Capabilities;
#if DBG
for (int ds=PowerSystemWorking; ds<PowerSystemMaximum; ds++)
DebugPrint('Capabilities from bus: DeviceState[%d]=%d',
ds, deviceCapabilities->DeviceState[ds]);
#endif
DEVICE_POWER_STATE dps;
SetMostPoweredState(PowerSystemWorking, PowerDeviceD0); // S0
SetMostPoweredState(PowerSystemSleeping1, PowerDeviceD3); // S1
SetMostPoweredState(PowerSystemSleeping2, PowerDeviceD3); // S2
SetMostPoweredState(PowerSystemSleeping3, PowerDeviceD3); // S3
SetMostPoweredState(PowerSystemHibernate, PowerDeviceD3); // S4
SetMostPoweredState(PowerSystemShutdown, PowerDeviceD3); // S5
}
return CompleteIrp(Irp, status, Irp->IoStatus.Information);
}
The bus driver for the Wdm2 device sets different values in DeviceState in Windows 98 and Windows 2000 Beta 2, as shown in Table 10.4. Windows 98 sets the most powered device state for S0–S4 to D0 and for S5 to D3. The most powered values for Wdm2 do not alter these values. In contrast, Windows 2000 Beta 2 sets the most powered device state for S1-S3 to D3 but does not set values for the other system states.
Table 10.4 DeviceState values
System state | S0 |
---|