Advanced Power Management for KMDF Drivers


 KMDF  As the examples in the previous section show, the framework handles most of the work in implementing Plug and Play and power management, even for a driver that supports a hardware device. This section describes how to go beyond the basics to add support for two advanced KMDF features:

  • Device idle support

    A driver can power down its device when the device becomes idle and the system remains in the working state (S0).

  • Device wake support

    Some devices can bring themselves, and perhaps the system, into a fully powered working state from a lower-powered state. Properly supporting wake requires specific capabilities in both the device hardware and the driver.

Device Power-Down Idle Support for KMDF Drivers

In many circumstances, powering down a device when it is idle-but while the system remains in the S0 state-has significant advantages:

  • Idle support saves power.

  • Idle support can help reduce environmental factors such as thermal load and noise.

If your device hardware can power down while it is idle, the driver should support this feature. Adding device idle support to a KMDF driver requires only a few extra callbacks beyond those required for basic Plug and Play support.

Idle Settings and Management in KMDF Drivers

To configure idle support, a driver sets idle characteristics in the WDF_DEVICE_ POWER_POLICY_IDLE_SETTINGS structure within its EvtDriverDeviceAdd or EvtDevicePrepareHardware function.

After the driver creates the device object, the driver uses the WDF_DEVICE_POWER_ POLICY_IDLE_SETTINGS_INIT macro to initialize the structure. This macro takes two arguments:

  • A pointer to the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure to initialize.

  • An enumeration value that indicates whether the driver supports idle and whether the device and driver support wake when the system is in S0.

    Possible values are listed in the IdleCaps row of Table 7-5. A driver that supports idle but does not support wake from S0 should specify IdleCannotWakeFromS0. A driver for a USB device that supports selective suspend should specify IdleUsbSelectiveSuspend in its call to the initialization macro.

    If the driver specifies IdleUsbSelectiveSuspend or IdleCanWakeFromS0, the framework uses the reported power capabilities for the device as the default DxState.

    If the driver specifies IdleCannotWakeFromS0, the framework sets PowerDeviceD3 as the default DxState.

Table 7-5: KMDF Device Idle Settings
Open table as spreadsheet

Field name

Description

Possible values

Enabled

Whether to enable device power-down on idle.

WdfTrue

WdfFalse

WdfDefault (enabled unless explicitly disabled by a user with administrator privileges)

IdleCaps

Whether the driver supports idle and whether the device and driver support wake in S0.

For a USB driver, whether the device supports USB selective suspend. USB drivers must not specify IdleCanWakeFromS0.

IdleCannotWakeFromS0

IdleCanWakeFromS0

IdleUsbSelectiveSuspend

DxState

The device power state to which the framework transitions the idle device.

PowerDeviceD0

PowerDeviceD1

PowerDeviceD2

PowerDeviceD3 (default if IdleCaps is set to IdleCannotWakeFromS0)

IdleTimeout

The amount of time, in milliseconds, that must elapse without receiving an I/O request before the framework considers the device idle.

ULONG or IdleTimeoutDefaultValue (currently set to 5000 milliseconds or 5 seconds)

UserControlOfIdleSettings

Whether the framework provides a property page in Device Manager to allow administrators to control the idle policy for the device.

IdleDoNotAllowUser-Control IdleAllowUserControl

After calling the macro, the driver can also set other fields in the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure. These fields are listed in Table 7-5.

After the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure has been initialized, the driver calls WdfDeviceAssignS0IdleSettings, passing the handle to the device object and a pointer to the initialized WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure.

As mentioned earlier, a driver can call WdfDeviceAssignS0IdleSettings any time after it creates the device object. Although most drivers call this method from the EvtDriverDeviceAdd callback, this may not always be possible or even desirable. If a driver supports multiple devices or device versions, the driver might not know whether the device is capable of wake from S0 until it interrogates its hardware. Such drivers can postpone calling WdfDeviceAssignS0IdleSettings until the EvtDevicePrepareHardware callback. The driver must indicate whether the device supports wake from S0 the first time that it calls WdfDeviceAssignS0IdleSettings. The framework does not recognize changes in wake from S0 support in subsequent calls to WdfDeviceAssignS0IdleSettings.

 Note  Whether an individual device can support wake from S0 depends on the capabilities of both the device and the slot or system to which the device is attached. Therefore, a call to WdfDeviceAssignS0IdleSettings that specifies IdleCanWakeFromS0 can fail with STATUS_POWER_STATE_INVALID on hardware configurations where wake from S0 is not supported. You must ensure that this error does not result in a failure to load your driver. If one of the initialization callbacks-such as EvtDriverDeviceAdd or EvtDevicePrepareHardware-returns this value to the framework, the framework disables the device.

Any time after its initial call to WdfDeviceAssignS0IdleSettings, the driver can change the idle time-out value, the device state in which the device idles, and whether device idle support is enabled. To change one or more settings, the driver simply initializes another WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure as described earlier and calls WdfDeviceAssignS0IdleSettings again.

Sometimes, a device should not be idled even if no I/O requests are present within the time-out period. A driver can prevent the framework from powering down an idle device in such situations by calling WdfDeviceStopIdle to prevent the device from idling and calling WdfDeviceResumeIdle when it is again acceptable for the device to be powered down for idle.

For example, the Serial sample does not power down its idle device if a handle is open. The Serial sample calls WdfDeviceStopIdle when it receives an open request and calls WdfDeviceResumeIdle when it receives a close request. The same is true for USB drivers. This behavior, however, is not appropriate for many other drivers, because most drivers always have an open handle.

These two methods manage a reference count on the device, so if your driver calls WdfDeviceStopIdle several times, the device will not go idle until the driver has called WdfDeviceResumeIdle the same number of times.

If the device is already in its low-power idle state, WdfDeviceStopIdle causes the framework to return the device to the D0 state. If the device is in the D0 state, WdfDeviceResumeIdle does not cause the framework to restart the device; instead, WdfDeviceResumeIdle restarts the idle time-out timer.

WdfDeviceStopIdle does not prevent the framework from transitioning the device to a sleep state when the system changes to an Sx sleep state. Its only effect is to prevent transitions to Dx sleep states while the system is in the S0 working state.

image from book
Stop Idle and Deadlocks

WdfDeviceStopIdle takes a Boolean WaitForD0 parameter, which specifies whether the method returns immediately or only after the device has returned to D0. If the driver passes TRUE, the transition to D0 is essentially a synchronous operation and can result in deadlocks. Here's why.

The framework serializes calls to most Plug and Play and power management callbacks-that is, it calls them one at a time and waits for each to return before calling the next. If a driver calls WdfDeviceStopIdle with WaitForD0 set to TRUE from a Plug and Play or power management callback, the framework cannot call the other functions that are required to return the device to D0 until the calling function has returned-and it never will. Therefore, you must be careful to call this method only from functions that you know are not part of power-up processing.

Do not call WdfDeviceStopIdle with WaitForD0 set to TRUE from:

  • Any Plug and Play or power management callback.

  • Any I/O event callback for a power-managed queue or any code that is called from such a callback.

If WaitForD0 is FALSE, the deadlock problem does not exist because the method returns immediately and does not block the framework's calls to the Plug and Play and power management callbacks.

Chapter 10, "Synchronization," has more information about how and when the framework serializes callbacks.

image from book

The framework integrates its idle power-down handling with the driver's other Plug and Play and power management activities. The framework transitions the device to the power state that the driver specified in its last call to WdfDeviceAssignS0IdleSettings when all of the following conditions are met:

  • Idle support is enabled.

  • The driver has not deactivated idling by calling WdfDeviceStopIdle.

  • The time-out period expires.

  • No I/O requests are active on the device.

The framework returns the device to D0 whenever one of the following occurs:

  • A new I/O request arrives at any of the device's power-managed queues.

  • The driver calls WdfDeviceStopIdle.

  • The driver disables idle support by calling WdfDeviceAssignS0IdleSettings, passing a WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure in which Enabled is set to WdfFalse.

  • The system transitions to a system power state that is incompatible with the device power state.

How to Choose Idle Times and Idle States in KMDF Drivers

A few words on how to choose appropriate idle times and device power states are appropriate here. In general the latency differences between returning a device to D0 from D1, D2, and D3 are on the order of a few milliseconds. There are a few exceptions. Video display devices, for example, can demonstrate differences in latency of several seconds. However, for nearly all other devices the difference in latency between a device in D1 and a device in D3 is so short that an end user is unlikely to perceive the difference. Consequently, considering the greater power savings achieved by idling a device in its power-off state, the framework by default transitions idle devices to D3.

Formerly, some vendors hesitated to implement idle support for their devices because they believed that users perceived any latency in their devices as decreased performance. However, this approach prevents these devices from achieving the power, heat, and noise savings that idle support can provide. Microsoft studies have shown that users perceive almost any latency as acceptable if it occurs only when the machine-or perhaps the device-is completely idle. A KMDF driver can prevent its device from prematurely entering the idle state by increasing the IdleTimeout value and calling WdfDeviceAssignS0IdleSettings each time the device becomes busy.

Device Wake Support for KMDF Drivers

The system power states in which a device can trigger a wake signal depend on the design of the device and the design of the system. Three different models for using the wake signal on a device are in common use:

  • Wake from S0: Triggering the wake signal from S0

    If the system is in S0 and the device is idle and in a sleep state, an external stimulus causes the device to trigger a wake signal, which in turn causes the framework and the driver to put the device back in the working state. The stimulus could be the click of a mouse button or the insertion of an Ethernet cable for a NIC.

  • Wake from Sx: Triggering the wake signal from S1, S2, S3, or S4

    If the system is in a sleep state, the driver can trigger a wake signal to return the system to the working state.

    Again, the stimulus to trigger the wake signal arrives externally, but the conditions that cause a wake signal are often different. For example, you probably would not want your machine to wake if you insert a network cable, but you might want it to wake if a special packet arrives over the network. For this reason, the framework supports different callbacks for arming your device to wake from S0 and Sx.

  • Wake from S5: Triggering the wake signal from S5

    Some devices can trigger the wake signal from S5, which causes the machine to power on from the "entirely off" state.

    This capability is often used for remote management over the network. However, this feature is outside the scope of drivers and Windows because it requires BIOS integration. Waking the system from S5 is not considered wake from a software perspective because the machine is not asleep-it's off. As a hardware developer, you must implement wake from S5 in the context of the BIOS, not in the operating system and drivers.

Wake from Sx is, perhaps, the most common wake category. Consider the following example. While the system is powered down to S3 and the devices connected to the system are similarly powered down, a "magic packet" arrives via Ethernet. As a result of receiving this packet, the network adapter hardware-which was appropriately configured before entering its low-power state-triggers a wake event (that is, PME# on the PCI bus) that causes the system to transition to S0. As a result, the system and its connected devices wake and return to the fully operational working state.

Unlike wake from Sx, wake from S0 is tied to device support for power-down idle. When the device becomes idle, it enters a low-power state while the system remains in S0. Wake from S0 simply means that the device can trigger a wake signal from its low-powered idle state. Wake support and idle support are related in the following ways:

  •  How wake and idle are related  Devices that support idle power-down while the system is in S0 do not necessarily support wake from S0.

  • Devices that support wake from S0 also implicitly support power-down idle.

  • Devices that support wake from Sx do not necessarily support power-down idle, but they might.

The wake setting that your driver should support depends on the scenarios you choose to support for the device. For example, a mouse, a network adapter, and a serial port might support wake as follows:

  • A mouse triggers a wake signal when a user moves it or clicks a button. This can occur in S0 or in Sx, depending on system power policy.

  • A network adapter goes idle when a cable is not present and triggers wake in S0 when the user plugs in a cable. A NIC can also trigger wake in Sx when a "magic packet" arrives. On a system with a specially designed BIOS, a network adapter could trigger wake from S5 when a custom management application starts the system remotely for servicing.

  • The driver has no way to know what type of device is plugged into a serial port. Therefore, whenever the system is in S0 and a handle is open to the serial port, the serial port must be in D0. A serial port can trigger wake from Sx if the "Ring Indicate" pin is triggered, indicating that a modem is plugged into the port and the associated phone is ringing.

The following sections describe how to implement both wake from Sx and wake from S0 in a KMDF driver.

How to Implement Wake from Sx in KMDF Drivers

To enable support for wake from Sx, a driver uses these two structures:

  • WDF_POWER_POLICY_EVENT_CALLBACKS

    This structure contains pointers to callback functions for device power policy events:

    • EvtDeviceArmWakeFromS0

    • EvtDeviceDisarmWakeFromS0

    • EvtDeviceWakeFromS0Triggered

    • EvtDeviceArmWakeFromSx

    • EvtDeviceDisarmWakeFromSx

    • EvtDeviceWakeFromSxTriggered

    This structure is filled into the DEVICE_INIT structure before the creation of the device object.

  • WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS

    This structure contains settings for device wake, including the power state from which device wakes the system and user control of wake.

    The driver fills in this structure by calling WdfDeviceAssignSxWakeSettings after the creation of the device object.

Power Policy Event Callbacks for Wake from Sx

The driver initializes the WDF_POWER_POLICY_EVENT_CALLBACKS structure in its EvtDriverDeviceAdd callback. This structure is input to the WDFDEVICE_INIT structure and so must be set up before the driver creates the device object.

To initialize the structure, the driver uses the WDF_POWER_POLICY_EVENT_ CALLBACKS_INIT macro, which supplies pointers to its EvtDeviceArmWakeFromSx, EvtDeviceDisarmWakeFromSx, and EvtDeviceWakeFromSxTriggered callbacks in the fields of the same names.

The framework calls the driver's EvtDeviceArmWakeFromSx callback function to request that the driver enable-or arm-its device to wake from S x. Within this function, the driver performs the device-specific processing to complete this task. If the driver is not required to perform any device-specific tasks-such as reconfiguring an internal interrupt signal on the device-to arm its device for wake, the driver is not required to supply this callback.

The EvtDeviceDisarmWakeFromSx callback function should reverse any actions in the EvtDeviceArmWakeFromSx function. The framework calls it to request that the driver disable-or disarm-its device to wake from Sx. As with EvtDeviceArmWakeFromSx, if no device-specific processing is required to disarm the device, the driver does not register for this callback.

When the driver's device triggers a wake signal, the framework calls the EvtDeviceWakeFromSxTriggered callback function. Because the framework handles all aspects of waking the system, this callback is merely informative. Consequently, most drivers do not register for this callback.

 Note  The framework calls EvtDeviceWakeFromSxTriggered and EvtDeviceWakeFromS0Triggered only if the system's BIOS and the motherboard are implemented correctly and work perfectly-which is sometimes not the case. If correct operation of the driver depends on knowing when the device triggered the wake signal, the device itself must supply this information and the EvtDeviceDisarmWakeXxx callbacks should read it from the device.

After the driver fills in the fields that apply to its implementation, it calls WdfDeviceInitSetPowerPolicyEventCallbacks to register the callbacks in the WDFDEVICE_INIT structure. It can then perform additional initialization tasks or create a device object.

Power Policy Sx Wake Settings

After the driver creates the device object, it can initialize the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS structure. This structure contains information about the device's wake from Sx policy and is input to WdfDeviceAssignSxWakeSettings to register this support with the framework. Table 7-6 lists the fields in this structure.

Table 7-6: Device Sx Wake Settings
Open table as spreadsheet

Field name

Description

Possible values

Enabled

Whether the device can wake the system from a low-powered state.

WdfTrue

WdfFalse

WdfDefault (enabled unless explicitly disabled by a user with administrator privileges)

DxState

The device power state to which the framework transitions the device when the system enters a wakeable low-power state.

PowerDeviceD1

PowerDeviceD2

PowerDeviceD3

UserControlOfWakeSettings

Whether the framework provides a property page in Device Manager to allow administrators to control the device's ability to wake the system.

WakeDoNotAllowUserControl

WakeAllowUserControl

To initialize the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS structure, the driver uses the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT macro. It then sets values for its device into the individual fields of the structure.

The driver fills in the DxState field with the device power state into which the framework should put the device when it is armed for wake from Sx. By default, the framework uses the value supplied in the device power capabilities.

The driver also fills in the UserControlOfWakeSettings field to indicate whether appropriately privileged users can control the wake policy of the device. If the value of this field is WakeAllowUserControl, the framework automatically creates a Device Manager property page for the driver that allows a user with administrator privileges to enable or disable device wake. If both wake and idle are supported by the device and both allow user control of their policies, the wake and idle options appear together on a single Device Manager property page for the device, by default. The property page modifies the IdleInWorkingState and WakeFromSleepState registry values, which are stored in the Parameters\Wdf subkey for the devnode. Users and drivers must not access these registry values directly.

The driver can disable user control of wake policy by setting this field to WakeDoNotAllowUserControl. Most drivers, however, should allow users to control wake policy because some hardware configurations support wake poorly.

When the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS structure is fully initialized, the driver calls WdfDeviceAssignSxWakeSettings, passing a pointer to this structure and the handle of the WDFDEVICE object.

How to Implement Wake from S0 in KMDF Drivers

Implementing support for device wake from S0 is similar to implementing support for wake from Sx. Initialization typically occurs in the driver's EvtDriverDeviceAdd function. However, because support for wake from S0 is related to device idle support, the driver must implement idle support and indicate that it supports wake from S0 when it enables idle support.

To indicate its support for wake from S0, a driver uses these structures:

  • WDF_POWER_POLICY_EVENT_CALLBACKS

  • WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS

The WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS structure is not used to configure wake from S0 support.

Power Policy Event Callbacks for Wake from S0

The driver initializes the WDF_POWER_POLICY_EVENT_CALLBACKS structure in its EvtDriverDeviceAdd callback. This structure is input to the WDFDEVICE_INIT structure and so must be set up before the driver creates the device object.

As previously described, the driver uses the WDF_POWER_POLICY_EVENT_CALLBACKS_INIT macro to initialize the structure. It sets pointers to the EvtDeviceArmWakeFromS0, EvtDeviceDisarmWakeFromS0, and EvtDeviceWakeFromS0Triggered callbacks in the fields of the same names.

The EvtDeviceArmWakeFromS0 and EvtDeviceDisarmWakeFromS0 callback functions perform device-specific actions that arm and disarm the device to wake when the system is in S0, such as waking a network adapter when the user plugs in a cable. These functions are required only if the driver and device require such actions:

  • If the device requires the same actions both to arm the device for wake from S0 and to arm the device for wake from Sx, the driver can specify the same callback function in both the EvtDeviceArmWakeFromS0 and EvtDeviceArmWakeFromSx fields of the WDF_POWER_POLICY_EVENT_CALLBACKS structure.

  • If no device-specific actions are required to prepare the device to wake the system from S0, for example, the EvtDeviceArmWakeFromS0 callback function is not necessary. This is likewise true for EvtDeviceDisarmWakeFromS0.

EvtDeviceWakeFromS0Triggered, like EvtDeviceWakeFromSxTriggered, is an informational callback and certain caveats apply, as the previous section points out.

When the WDF_POWER_POLICY_EVENT_CALLBACKS structure is fully initialized, the driver calls WdfDeviceInitSetPowerPolicyEventCallbacks to register the callbacks in the WDFDEVICE_INIT structure.

If a driver supports both wake from S0 and wake from Sx, it fills in WDF_POWER_POLICY_ EVENT_CALLBACKS with the necessary callbacks to support both wake from S0 and wake from Sx before calling WdfDeviceInitSetPowerPolicyEventCallbacks.

Power Policy Idle Settings for Wake from S0

After the driver creates the device object, it initializes a WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure by using the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT macro. As discussed earlier, this macro takes an argument that indicates whether the device and driver support wake in S0. A driver that supports wake from S0 must specify IdleCanWakeFromS0-or IdleUsbSelectiveSuspend for a USB device-in its call to the initialization macro. The driver then sets other fields in the structure and calls WdfDeviceAssignS0IdleSettings, as described in "Device Power-Down Idle Support" earlier in this chapter.

KMDF Example: Support for Device Idle and Wake

This example continues the hardware function driver in "KMDF Example: Plug and Play and Power Code in a Simple Hardware Function Driver" earlier in this chapter. You can see the code for the driver's EvtDriverDeviceAdd callback in Listing 7-8 in that section.

The Osrusbfx2 driver adds support for device idle and USB selective suspend by initializing the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure and calling WdfDeviceAssignS0IdleSettings. Before the driver can initialize idle and wake support, it must determine whether the device supports these features. To find out, the driver interrogates the device from its EvtDevicePrepareHardware callback, which is shown in Listing 7-11. This function appears in the Driver.c source file.

Listing 7-11: Sample USB driver's EvtDevicePrepareHardware callback

image from book
 NTSTATUS OsrFxEvtDevicePrepareHardware(     IN WDFDEVICE Device,     IN WDFCMRESLIST ResourceList,     IN WDFCMRESLIST ResourceListTranslated     ) {     NTSTATUS                            status;     PDEVICE_CONTEXT                     pDeviceContext;     WDF_USB_DEVICE_INFORMATION          deviceInfo;     ULONG                               waitWakeEnable;     UNREFERENCED_PARAMETER(ResourceList);     UNREFERENCED_PARAMETER(ResourceListTranslated);     pDeviceContext = GetDeviceContext (Device);     // Create a USB device handle to communicate with the     // underlying USB stack. status = WdfUsbTargetDeviceCreate (Device,                                        WDF_NO_OBJECT_ATTRIBUTES,                                        &pDeviceContext->UsbDevice);     if (!NT_SUCCESS(status)) {         return status;     }     status = SelectInterfaces(Device);     if (!NT_SUCCESS(status)) {         return status;     }     // Retrieve USBD information     WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); status = WdfUsbTargetDeviceRetrieveInformation (pDeviceContext->UsbDevice,                                                     &deviceInfo);     waitWakeEnable = deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE;     // Enable wake and idle timeout if the device supports it.     if(waitWakeEnable){         status = OsrFxSetPowerPolicy(Device);         if (!NT_SUCCESS (status)) {             return status;         }     }     status = OsrFxConfigContReaderForInterruptEndPoint (pDeviceContext);     return status; } 
image from book

Listing 7-11 shows how a driver might determine whether its device supports wake. In this sample, the driver creates a USB target device object and then calls WdfUsbTargetDeviceRetrieveInformation to get the capabilities of the device and the underlying port driver. These capabilities are returned as a set of bit flags in the Traits field of a WDF_USB_DEVICE_INFORMATION structure. The driver tests the value of the WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE bit and, if it is true, calls the OsrFxSetPowerPolicy internal helper function to enable idle and wake support.

Listing 7-12 shows the code for OsrFxSetPowerPolicy. This function also appears in Device.c.

Listing 7-12: Initializing wake and idle support in a KMDF USB driver

image from book
 NTSTATUS OsrFxSetPowerPolicy(     IN WDFDEVICE Device ) {     WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;     WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;     NTSTATUS    status = STATUS_SUCCESS;     // Initialize the idle policy structure.     WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings,                                                IdleUsbSelectiveSuspend);     idleSettings.IdleTimeout = 10000; // 10-sec     status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings); if ( !NT_SUCCESS(status)) {         return status;     }     // Initialize the wait-wake policy structure. WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);     if (!NT_SUCCESS(status)) {         return status;     }     return status; } 
image from book

The OsrFxSetPowerPolicy function is called from the driver's EvtDevicePrepareHardware callback to enable idle and wake for the USB device.

In the example, the driver calls WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT, specifying IdleUsbSelectiveSuspend. The driver sets IdleTimeout to 10,000 milliseconds (10 seconds) and accepts the framework defaults for DxState and UserControlOfIdleSettings. As a result, the framework transitions the device to the D3 state when it is idle and creates a Device Manager property page that allows users with administrator privilege to enable or disable device idle support. The driver then calls WdfDeviceAssignS0IdleSettings to enable idle support and register these settings with the framework.

For USB devices that support selective suspend, the underlying bus driver prepares the device hardware to wake. Consequently, the function driver should supply an EvtDeviceArmWakeFromS0 callback only if additional device-specific programming is required. The framework sends a selective suspend request to the USB bus driver when the idle time-out expires.

Framework Actions Supporting Device Idle

The framework counts the I/O activity on all power-managed queues that each device object owns. If the driver supports idle for the device object, the framework starts a timer whenever the I/O count reaches zero. The timer is set to expire at the number of milliseconds specified in the IdleTimeout field most recently passed to WdfDeviceAssignS0IdleSettings.

If an I/O request arrives at a power-managed queue that belongs to the device or if the driver calls WdfDeviceStopIdle before the IdleTimeout period expires, the framework cancels the timer.

If instead the timer expires, the framework takes the required steps to transition the device out of D0 and into the device power state that the driver specified in the DxState field most recently passed to WdfDeviceAssignS0IdleSettings.

Regardless of the reason for the transition, the framework always handles the transition out of the D0 state in the same way. Thus, when a device transitions from D0 to Dx, the framework invokes the driver's callback functions according to the power-down sequences described in "Device Power-Down and Removal" earlier in this chapter.

If the device is idling in its low-power state, the framework automatically returns the device to D0 whenever the count of I/O activity on any of the device's power-managed queues becomes nonzero or when the driver calls WdfDeviceStopIdle. Again, the transition to D0 is always handled according to the power-up sequences described in "Device Enumeration and Startup" earlier in this chapter.

Framework Actions Supporting Device Wake

If a driver supports wake for its device, the framework calls the driver's EvtDeviceArmWakeFromSx callback during a system transition to a lower power state other than S5 (the fully-off state), if the driver supports wake from the new system state. For example, assume the system is transitioning to S3. If the driver supports wake from S3, the framework calls the driver's EvtDeviceArmWakeFromSx callback. However, if the driver supports wake only from S1, the framework does not call the driver to arm the wake signal.

image from book
System Power State Queries

Windows queries before changing the system power state. If the device cannot support wake from the proposed system power state, why doesn't the framework fail the query?

The framework does not fail the system power query for two reasons:

  • If the framework fails the current query for this Sx state and some other driver fails the next request for a different Sx state, the system might never power down.

  • The framework does not want to force the system into a lighter sleep state just so the device can wake it up.
    -Doron Holan, Windows Driver Foundation Team, Microsoft

image from book

The following is the prototype for the EvtDeviceArmWakeFromSx callback function:

 NTSTATUS EvtDeviceArmWakeFromSx(WDFDEVICE Device) 

The framework calls this function before taking any action to transition the device to its Dx state, such as calling EvtDeviceD0Exit. Within the EvtDeviceArmWakeFromSx function, the driver arms the device for wake from Sx. If the driver cannot successfully arm the device, the callback returns an error and the framework continues the transition to the Dx state without the device being armed for wake. If the system and device are later powered up again and then put to sleep, the framework by default again calls the driver's EvtDeviceArmWakeFromSx callback. That is, the framework does not "remember" that the driver failed to arm the device during a previous power-down.

The driver can disable further requests to arm the device for wake from Sx by returning the WDFSTATUS_ARM_FAILED_DO_NOT_RETRY status from the EvtDeviceArmWakeFromSx callback.

If the device triggers the system to wake, the framework calls the driver's EvtDeviceWakeFromSxTriggered callback. Because the framework handles all the work that is necessary to wake the system, this callback is strictly informative for the driver.

When the system returns to S0, the framework calls the driver's EvtDeviceDisarmWakeFromSx function after the device returns to operation, that is, after the framework calls EvtDeviceD0Entry. The EvtDeviceDisarmWakeFromSx callback disarms the device for wake and reverses any other device-specific actions that were taken in its EvtDeviceArmWakeFromSx function.

Supporting wake from S0 is almost the same as supporting wake from Sx. The only difference is that the framework invokes the driver's EvtDeviceArmWakeFromS0 and EvtDeviceDisarmWakeFromS0 event callbacks when the device is ready to transition to or from the idle state, respectively. As with EvtDeviceArmWakeFromSx and EvtDeviceDisarmWakeFromSx, these callbacks are invoked before other driver callbacks that involve leaving or entering D0.




Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net