WDF implements Plug and Play and power management with several internal state machines. Both KMDF and UMDF use the same state machines. An event is associated with the specific actions that a driver might be required to perform at a particular time, and the driver implements the event callbacks to perform the actions that its device requires. The callbacks are called in a defined order and each conforms to a "contract," so that both the device and the system are guaranteed to be in a particular state when the driver is called to perform an action.
Although WDF provides great flexibility so that a driver can control detailed aspects of its device's Plug and Play capabilities, WDF also implements defaults that enable many filter drives and software-only drivers to omit any Plug and Play code whatsoever. By default, WDF supports all Plug and Play features that such drivers need.
By default, WDF assumes the following:
The device supports D0 and D3.
The device and driver do not support idle or wake.
The I/O queues for an FDO or a PDO are power managed.
The history of the state machines in the framework provides an interesting view into how much we underestimated the complexity involved in implementing them. When Jake Oshins first introduced his idea of using formalized state machines with a Unified Modeling Language (UML) diagram as a visual aid, there were two state machines (PnP and Power) with fewer than ten states between them. In fact, power just had two states, on and off!
Needless to say, the number of states grew dramatically to nearly 300 states among all of the state machines. Not only did the number of states grow, but so did the number of state machines. In addition to the PnP, power, and power policy machines, the framework also uses state machines to manage the idle logic and self-managed I/O callbacks.
Taking a step back and looking at the final implementation, we had no idea what we were in for when we started, and we could never have predicted the final results. The biggest satisfaction that I derived from working on the state machines was that all of the complexity remained internal to the framework. What the driver writer sees is a very clear contract with very clear guidelines, never having to worry about this set of problems again.
-Doron Holan, Windows Driver Foundation Team, Microsoft
The frameworks implement power management for I/O queues, so that the queue automatically starts and stops when the device enters and leaves the working state. Such a queue is "power managed." The framework dispatches I/O requests from a power-managed queue to the driver only when the device hardware is accessible and in the working power state. The driver is not required to maintain device state or to check device state each time it receives an I/O request from a power-managed queue.
By default, the I/O queues of FDOs and PDOs are power managed. A driver can easily change this default to create a non-power-managed queue or to configure power-managed queues for a filter DO. If an I/O request arrives while the device is in a low-power idle state, the framework can restore device power before it delivers the request to the driver.
Most of the Plug and Play and power callbacks are defined in pairs: one event occurs upon entry to a state and the other occurs upon exit from the state. Generally, one member of the pair performs a task that the other reverses. A driver can implement one, both, or neither of a pair. In a UMDF driver where both methods are defined on a single interface, the driver must implement the entire interface on the device callback object but can supply minimal implementations of the methods that it does not require.
The frameworks are designed to work with drivers on an opt-in basis. A driver implements callbacks for only the events that affect its device. For example, some drivers must save device state immediately before the device leaves the D0 power state and restore device state immediately after the device reenters the D0 power state. As another example, a device might have a motor or fan that the driver must start when the device enters D0 and stop before the device leaves D0. A driver can implement callback functions that are invoked at those times. If the device does not require service at those particular times, its driver does not implement the callbacks.
Table 7-1 summarizes the types of Plug and Play and power features that a driver might require and the UMDF interfaces and KMDF event callbacks that the driver implements to support those features.
If your driver…
Implement this UMDF interface and its methods on the device callback object…
Implement this KMDF event callback…
Uses self-managed I/O
Requires service immediately before the device is initially powered up and after it powers down during resource rebalancing or device removal
EvtDevicePrepareHardware and EvtDeviceReleaseHardware
Requires service immediately after the device enters D0 and before it leaves D0
EvtDeviceD0Entry and EvtDeviceD0Exit
Requires the opportunity to evaluate and veto each attempt to stop or remove the device
EvtDeviceQueryStop and EvtDeviceQueryRemove
Requires additional service at surprise-removal beyond the normal device removal processing
KMDF Because KMDF drivers have greater access to device hardware than UMDF drivers do, KMDF supports additional features, such as system wake. Table 7-2 lists additional callbacks that apply only to KMDF drivers.
If your driver…
Implement this KMDF event callback…
Manages device resource requirements
Manages the device's wake signal
EvtDeviceArmWakeFromSx and EvtDeviceDisarmWakeFromSx
EvtDeviceArmWakeFromS0 and EvtDeviceDisarmWakeFromS0
EvtDeviceEnableWakeAtBus and EvtDeviceDisableWakeAtBus
EvtDeviceWakeFromSxTriggered and EvtDeviceWakeFromS0Triggered
Performs hardware-related tasks around interrupts
EvtInterruptEnable and EvtInterruptDisable
EvtDeviceD0EntryPostInterruptsEnabled and EvtDeviceD0ExitPreInterruptsDisabled
WDF automatically translates system power events to device power events If you're familiar with WDM drivers, you probably remember that any time the system power state changes, the WDM power policy owner must determine the correct power state for its device and then send power management requests to put the device in that state at the appropriate time. The WDF state machine automatically translates system power events to device power events and notifies the driver to do the following:
Transition the device to low power when the system transitions to Sx.
Return the device to full power when the system returns to S0.
Enable the device's wake signal so that it can be triggered while the device is in a Dx state and the system is in the working state. (KMDF only)
Enable the device's wake signal so that it can be triggered while the device is in a Dx state and the system is in a sleep state. (KMDF only)
KMDF KMDF automatically provides for the correct behavior in device parent/child relationships for bus drivers. If both a parent and a child device are powered down, KMDF ensures that the parent is powered up before it transitions the child to the D0 state.
To manage idle devices, the framework notifies the driver to transition the device from the working state to the designated low-power state when the device is idle and to return the device to the working state when requests need to be processed. The driver supplies callbacks that initialize and deinitialize the device, save and restore device state, and enable and disable the device wake signal.
By default, a user who has the appropriate privileges can control both the behavior of the device while it is idle and the ability of the device to wake the system. KMDF implements the required WMI provider, and Device Manager displays a property page through which the user can configure the settings. The power policy owner for the device can disable this feature by specifying the appropriate enumeration value when it initializes certain power policy settings.
Most devices can be powered down without affecting the system's ability to access the paging file or to write a hibernation file. The drivers for such devices are considered "power pageable":
All UMDF drivers are power pageable.
Most KMDF drivers are power pageable.
KMDF A device that is in the hibernation path, however, must remain in D0 during some power transitions so that the system can write the hibernation file. A device that is in the paging path remains in D0 until the system has written the hibernation file, at which point the entire machine shuts off. The device stacks for the hibernation and paging devices are considered non-power pageable. A KMDF driver indicates that it can support the paging, hibernation file, or system dump file by calling WdfDeviceSetSpecialFileSupport and providing a callback for notification if the device is actually used for such a file.
For example, drivers in the video and storage stacks are non-power pageable because the system uses these devices during power-down. The monitor must remain on so that Windows can display information to the user. During transitions to S4, the target disk for the hibernation file and the disk that contains the paging file must remain in D0 so that the system can write the hibernation file. For the disks to retain power, every device that they depend on must also retain power-such as the disk controller, the PCI bus, the interrupt controller, and so on. All of the drivers in all of these device stacks must thus be non-power pageable.
Most drivers should use the framework's defaults, which are as follows:
FDOs by default are power pageable.
PDOs by default inherit the setting of the driver that enumerated them.
If the PDO is power pageable, all the device objects that are attached to it must also be power pageable. For this reason, a bus driver typically marks its FDO as non-power pageable so that its PDOs inherit the same attribute. The device objects that load above the PDO can then be either power pageable or non-power pageable.
Filter DOs use the same setting as the next lower driver in the stack. A driver cannot change the setting for a filter DO.
If the default is inappropriate, a function or bus driver can explicitly call the WdfDeviceInitSetPowerPageable or WdfDeviceInitSetPowerNotPageable method during device object initialization to change the default. These methods set and clear the DO_POWER_PAGABLE value in the Flags field of the underlying WDM device object for an FDO or PDO, but have no effect for filter DOs.
The framework can change the value of the DO_POWER_PAGABLE flag for any device object if the system notifies the driver that the device is used for a hibernation, paging, or dump file.
If you are certain that none of the drivers in the device stack must be non-power pageable, your driver can call WdfDeviceInitSetPowerPageable. This might be the case if you wrote all of the drivers in the stack or if the requirements for the device stack are clearly documented. A PDO must not be power pageable unless the device stacks of all of the child devices are also power pageable.
KMDF provides the following special handling for drivers that are non-power pageable:
The framework disables-but does not disconnect-the device's interrupt when the device leaves the D0 state. The framework cannot disconnect the interrupt because the required IoDisconnectInterruptXxx system call is pageable.
The framework implements a watchdog timer on all callbacks for power and wake events. If the driver causes paging I/O after the paging file's device has left D0, a deadlock occurs, thus hanging the system. When the timer expires, the system crashes so that the user can determine which driver caused the deadlock. You can use the !wdfextendwatchdog debugger extension to extend the time-out during debugging. KMDF does not provide a way to extend the time-out programmatically.
A driver can determine whether it is currently in a nonpageable power state by calling WdfDevStateIsNP(WdfDeviceGetDevicePowerState()) from within a power or power policy callback function.
WdfDeviceGetDevicePowerState returns an enumeration value of the WDF_DEVICE_POWER_STATE type, which identifies the detailed state of the framework's state machine. For example, WdfDevStatePowerD0 and WdfDevStatePowerD0NP are two distinct values that represent the pageable D0 state and the nonpageable D0 state, respectively.
WdfDevStateIsNP returns TRUE if the driver is currently in a nonpageable power state and FALSE otherwise. This value is valid only while the current callback function is running. After the callback returns, the power state can change. Therefore, if the driver must perform actions that involve paging, the driver should do so immediately upon determining that the device power state permits these actions.