Supporting Single-Component Devices with Single or Multiple Functional Power States
A KMDF driver for a single-component device can define one or more functional power states for the component and register callback functions that the power management framework (PoFx) calls when the Fx state of the component changes or its active/idle condition changes. Starting in UMDF version 2.0, a UMDF driver for a single-component device can define a single functional power state (F0).
For more information about PoFx, see Overview of the Power Management Framework.
To implement Fx state support for a single-component device, you must do the following in order before or during the first time a device starts.
- This step is for KMDF drivers only. Call WdfDeviceWdmAssignPowerFrameworkSettings to specify the power framework settings that WDF uses when registering with PoFx. In the WDF_POWER_FRAMEWORK_SETTINGS structure that the driver provides when it calls WdfDeviceWdmAssignPowerFrameworkSettings, the driver can provide pointers to several callback functions. If the driver supports only a single functional power state (F0), this step is optional.
This step applies to KMDF drivers and UMDF drivers. Call WdfDeviceAssignS0IdleSettings and set the IdleTimeoutType field of the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure to SystemManagedIdleTimeout or SystemManagedIdleTimeoutWithHint. Doing so causes WDF to register with PoFx.
Because a device can start more than once, for example in the event of resource rebalancing, a driver might perform the previous steps within the EvtDeviceSelfManagedIoInit callback function. If the driver has registered an EvtDeviceSelfManagedIoInit callback function, the framework calls it once for each device, after the framework has called the driver's EvtDeviceD0Entry callback function for the first time.
The remainder of the information in this topic applies only to KMDF drivers.
The framework calls the driver's EvtDeviceWdmPostPoFxRegisterDevice callback function after the framework has registered with PoFx. Here is an example of a typical power up sequence:
- EvtDeviceD0Entry (PrevState = WdfPowerDeviceD3Final)
- EvtDeviceWdmPostPoFxRegisterDevice // PoFx handle is available
The driver provides the EvtDeviceWdmPostPoFxRegisterDevice callback if it must perform any additional operations using the POHANDLE for the power framework registration. For example, it could specify latency, residency, and wake requirements. For more information about routines that use the POHANDLE, see Device Power Management Routines.
Your driver can also use the POHANDLE to exchange power control requests with PoFx:
- To send a power control request to PoFx, the driver provides a EvtDeviceWdmPostPoFxRegisterDevice callback function, and then uses the resulting POHANDLE to call PoFxPowerControl.
- To perform power control operations requested by PoFx, the driver provides a PowerControlCallback callback routine in its WDF_POWER_FRAMEWORK_SETTINGS structure.
WDF calls the EvtDeviceWdmPrePoFxUnregisterDevice callback function before deleting a specified registration with PoFx.
The driver can provide a pointer to a ComponentIdleStateCallback routine in the WDF_POWER_FRAMEWORK_SETTINGS structure that it provides to WdfDeviceWdmAssignPowerFrameworkSettings. PoFx calls this routine to notify the driver of a pending change to the Fx power state of the specified component. In this callback routine, the driver can perform hardware-specific operations related to the functional state change.
For example, before transitioning a component into a low-power Fx state, a driver might save hardware state and disable interrupts and DMA. The driver calls WdfInterruptReportInactive to inform the system that the interrupt is no longer active. Turning off interrupts during F-state transitions may reduce overall system power consumption.
The driver can also provide a pointer to a ComponentIdleConditionCallback routine in its WDF_POWER_FRAMEWORK_SETTINGS structure. PoFx calls this routine to notify the driver that a component has become idle. In this routine, the driver begins the process of stopping its power-managed queues and self-managed I/O operations:
- Call WdfIoQueueStop once for each of the device’s power-managed queues. In each call to WdfIoQueueStop, supply a EvtIoQueueState callback. Typically, the driver calls WdfIoQueueStop from within ComponentIdleConditionCallback.
- Ensure that requests that are dispatched to the driver from each of the power-managed queues are completed quickly. Depending on the driver, this may involve some or all of the following:
- If the driver does not hold requests for an extended time and does not forward them to an I/O target that does so, continue to step 3.
- If the driver holds certain requests for an extended time, requeue these requests to a manual queue. In its ComponentActiveConditionCallback routine, the driver can then retrieve the requests.
- If the driver forwards certain requests to an I/O target that holds them for an extended time, cancel these requests. Resubmit the requests in ComponentActiveConditionCallback.
When each queue has been stopped, the framework calls EvtIoQueueState. If the driver is stopping multiple power-managed queues, the framework calls EvtIoQueueState multiple times, once for each queue.
In order to determine which call is last, the driver might use a counter to track the number of times that the framework has called EvtIoQueueState. The Singlecomp sample illustrates this technique. This sample is available beginning in the Windows 8 WDK.
Here is an example of a typical power down sequence:
Restart power-managed queues and self-managed I/O operations in ComponentActiveConditionCallback.
If the driver previously called WdfInterruptReportInactive, re-enable inactive interrupts by calling WdfInterruptReportActive from either ComponentActiveConditionCallback or ComponentIdleStateCallback.