// 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 PowerUpDevice to power the device up if necessary by calling SendDeviceSetPower. Finally, PowerUpDevice resets the idle counter using PoSetDeviceBusy.

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 SendDeviceSetPower shown in Listing 10.5 checks that the device has really changed power state, and forces the change if necessary.

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 Wdm2Power application to test these features.

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 PnpQueryCapabilitiesHandler handles the Query Capabilities PnP IRP for Wdm2. It first forwards the IRP down the stack and waits for it to complete. It then alters the DEVICE_CAPABILITIES structure, if necessary.

The DeviceState field is an array that indicates the corresponding device power state for each system power state. Or more precisely, it specifies the most powered state that a device can be in at a system power level. For example, when the system is fully on in S0, the device can be fully on in D0 or it may have idled into D3.

PnpQueryCapabilitiesHandler ensures that the correct 'most powered device state' is specified by the bus driver. The SetMostPoweredState macro checks to see if a device state has been set and ups the DeviceState entry if appropriate.

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. PnpQueryCapabilitiesHandler will, therefore, modify DeviceState tor S0, S4, and S5.

Table 10.4 DeviceState values

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

0

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

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