An In-Depth Look at the Power Manager in Windows CE .NET 4.1
PS Technology Corp.
Microsoft® Windows® CE .NET 4.1
Summary: This article provides an in-depth look at the new capabilities provided by the Power Manager in Windows CE .NET 4.1. It begins with a summary of the new features, and then launches into a detailed technical discussion of how to use the new features to extend power savings and battery life for embedded systems and devices. Topics include how applications can interface with the Power Manager, how device drivers can intelligently manage device power state that is separate from the system power state, and how OEMs can modify the Power Manager component to provide custom power handling for their platforms.
In Microsoft® Windows® CE .NET, the Power Manager component was introduced to provide a framework for implementing sophisticated power management support. The Power Manager acts as a "mediator" between the kernel/ OEM Adaptation Layer (OAL) and device drivers and applications, and coexists with drivers and applications that are not power managed. Within this framework, device power state can be managed separately from the system state, so devices that are capable of intelligently managing their own power are now able to do so. With the release of Windows CE .NET 4.1, Microsoft introduced support for a number of new features for power management. You can take advantage of greater power savings capabilities by updating your platforms and device drivers to use these new features, which include the following:
- Automatic registration is now supported for additional device classes, such as NDIS miniports and Block storage devices. OEMs can also define new classes as being "power-aware" by using the registry.
- PCMCIA client drivers (including those for NDIS and file system clients) can now stay loaded during system suspend/resume (provided that the card is not physically removed).
- Support is provided for system-wide Activity Timers, and the Graphical Windowing and Event Subsystem (GWES), networking, and file system components have been updated to work with these activity timers.
- DEBUGMSG and RETAILMSG can be called by the power handlers (XXX_PowerUp and XXX_PowerDown functions).
- The restrictions on which routines can be called by the power handlers are now strictly enforced.
- The default Power Manager implementation no longer sends the IOCTL_POWER_QUERY request (in Windows CE .NET 4.0, this request was sent only in some cases, and was not always honored, so this was changed in Windows CE .NET 4.1 for consistency). OEMs can still customize the platform-dependent driver (PDD) to implement this support.
- RequestPowerNotification supports selecting subsets of the desired PBT_Xxx notifications.
- There is a new PBT_POWERINFOCHANGE notification that provides battery-level information.
- The Power Manager Module Device Driver (MDD) reference counts device objects to avoid holding critical sections across DeviceIoControl calls.
- There is a new CeSetPowerOnEvent API that allows power handlers to signal non-interrupt events during suspend/resume.
These new features will be discussed in more detail in the following sections.
The default Power Manager in Windows CE .NET 4.1 is implemented in a layered fashion, and consists of an MDD layer and a PDD layer. OEMs will typically customize the PDD layer for their platform. The Power Manager (PM.dll) is linked directly with DEVICE.exe, and supports three interfaces:
- Device Driver Interface
- Application Interface
- Notification Interface
The Device Driver Interface is used by drivers for power managed devices, the Application Interface is used by applications that need to impose device power requirements, and the Notification Interface is used by applications that must be notified about power events. To take advantage of the new power management capabilities, you should first fully understand the concepts of System Power States and Device Power States.
System Power States
The OEM can define any number of System Power States, which are described in the registry. The transitions between these states can occur in any way that makes sense for the hardware platform. These transitions may occur as a result of an OEM event, such as docking or undocking from a cradle, or moving from AC power to battery power. The transitions might also be invoked by an OEM application or utility calling the SetSystemPowerState application programming interface (API).
In general, the current System Power State defines the maximum device power state for all devices in the system, essentially providing the "ceiling" for the device power state. The following registry entries are used to define the mapping between System Power State and Device Power States:
- Name. Name of the system power state.
- Flags. Additional state information (hints). This entry maps to the POWER_STATE_XXX values in pm.h, which is located in PUBLIC\COMMON\SDK\INC. For example, 0x200000 is POWER_STATE_SUSPEND and indicates that entering this system power state should suspend the system.
- Default. Maximum power state for devices at this state. A DWORD corresponding to the device power state: 0 for D0, 1 for D1, etc. This is actually the unnamed registry value, often represented as the at sign (@) in regedit. In a Windows CE .NET .reg file, it is represented as "default". It is not a "default" device power state, because devices at a lower power state will not be affected by the transition into the new system power state.
- DeviceName. Optional device power state overrides for specific devices instead of Default. This entry is also a DWORD corresponding to the device power state: 0 for D0, 1 for D1, etc.
The Power Manager in Windows CE .NET 4.1 supports four System Power States:
- On. The user is actively using the device
- UserIdle. The user stopped interacting but may still be using the device
- SystemIdle. Entered after a period in UserIdle, but driver and system process are still active
- Suspend. Entered when driver and system processes stop interacting with the system
Device Power States
There are five pre-defined Device Power States, which also have corresponding keys in the Registry, as shown in the following table.
|Device Power State||Registry Key||Description|
|Full On||D0||Full power|
|Low On||D1||Fully functional at lower power or performance|
|Standby||D2||Partial power, standing by for wakeup request|
|Sleep||D3||Sleeping, minimal power needed to initiate own wakeup|
Table 1. Device Power States
As shown in this table, higher numbered states should consume less power than lower numbered states. For example, D3 has a higher number (3) than D2 (2), but D3 consumes less power than D2. The only required state is the D0 state, Full On; all of the other states are optional. From a user's viewpoint, both the D0 state and the D1 state should appear to be fully functional.
The device driver maps these five pre-defined states to states that make sense for the device. The Power Manager sends a request to each device driver when it loads, to find out which device power states are supported by the device. If possible, the driver should place the device in D0 when it loads, and place it in D4 when it unloads. If the Power Manager requests that a device be placed in a state that it does not support, the driver should put the device in the next higher-numbered state that it supports. For example, if D2 is not supported, the driver can place the device in D3 or D4 instead.
Device Power Management
This section describes how to implement support for device power management using the new Power Manager framework. As mentioned in the preceding section, one of the exciting new features of the Power Management model in Windows CE .NET is that devices can maintain a device power state that is separate from that of the system. This is particularly useful for devices that are capable of finer granularities of power savings than those defined for the system. For example, a rotating hard drive can go to a lower power-consuming state by spinning down its disk, even while the system remains fully powered.
To take advantage of the new power model, a driver must be able to:
- Report its power capabilities to the Power Manager on request
- Handle power requests sent by the Power Manager
- Power up the device after startup
- Power down the device for shutdown
- Enable the device for wakeup if it is capable of waking the system
There are two ways to register a driver as being power aware. The recommended method is to add a specific GUID to the IClass registry entry for the device. As an alternative, the driver could call the AdverstiseInterface API directly with the specific GUID; however, this is not the preferred method.
The IClass registry entry identifies the device as belonging to a specific class of power aware devices. In Windows CE .NET 4.0, the generic class was the only supported class, and you could use the DEVCLASS_POWER_MANAGER_STRING GUID to associate drivers with the generic power-managed device class. Beginning with Windows CE .NET 4.1, you can use PMCLASS_GENERIC_DEVICE as the GUID for the generic class, and there are two new classes of devices that can also be used: Power-manageable block storage devices are supported with the PMCLASS_BLOCK_DEVICE GUID, and power-manageable NDIS miniports are supported with the PMCLASS_NDIS_MINIPORT GUID. OEMs can also define their own classes of power-managed devices and specify the associated GUID in the Registry.
You can get a list of power-managed device classes by enumerating the Registry entries under the following key:
You can also use class-qualified device names when calling APIs for a specific device, for example:
This is required if the device does not belong to the generic power-manageable device class.
There are two mechanisms that are used to interface between a power-aware driver and the Power Manager:
- PM to Driver. The Power Manager sends I/O controls (IOCTLs) to the driver using the DeviceIoControl API.
- Driver to PM. The driver calls the DevicePowerNotify API to communicate with the Power Manager.
When the driver advertises its interface (generally when it is loaded), the Power Manager sends it an IOCTL_POWER_CAPABILITIES request to get information about the power states that are supported by the device. Power-aware drivers must respond to this I/O control (IOCTL). The Power Manager will subsequently assume management of the power states for the device. The Power Manager sends IOCTL_POWER_SET requests to the driver to direct the device to change power states. The Power Manager can also send the IOCTL_POWER_GET request to ask the device for its current power state. Drivers that support self-management of power for their devices call the DevicePowerNotify API to ask the Power Manager to place their device in a specific state.
The IOCTL_POWER_QUERY request, as mentioned previously, is never sent with the default implementation of the Power Manager in Windows CE .NET 4.1. In Windows CE .NET 4.0, it was sometimes used to ask a device whether it was ready to enter a new power state. OEMs can implement a consistent strategy for sending this request and honoring the response.
When a driver receives the IOCTL_POWER_SET request from the Power Manager, it should change the device to the new state, if possible. If the requested state is unsupported, the driver should write the adjusted power state that it will assume instead in the return buffer, so that the Power Manager knows the actual state the device will assume.
The Power Manager may direct the device to assume a state that the device does not support. If this happens, the driver must go to a supported state with the next lower power consumption, which will have a higher power number.
The Power Manager may also direct the device to change to the same state that it is presently in. If this occurs, the driver should simply respond with success.
Driver developers should be aware that the Power Manager is not required to set the device power state to the maximum value associated with a given System Power State. If the device is actively managing its own power with DevicePowerNotify, the Power Manager will not modify its device power state during the transition to a new system power state if the device's current state consumes less power than the maximum.
The Power Manager sends the IOCTL_POWER_GET request to retrieve the current device power state. The Power Manager actually maintains its own internally cached state for a given device, so it sends this request only if the application calls GetDevicePower with the POWER_FORCE flag set; otherwise it returns its cached power state for that device.
How Drivers Use DevicePowerNotify
When a power-aware driver decides that it needs to place its device in a specific power state, it calls the DevicePowerNotify API to notify the Power Manager of the desired state change. The Power Manager may not honor the request if an application or another driver has requested a specific power requirement that is inconsistent with the desired state. If the Power Manager honors the request, it will issue an IOCTL_POWER_SET to the device to direct it to change to a specific power state.
Drivers should change their state only when they receive an IOCTL_POWER_SET—not when DevicePowerNotify returns. A driver should not assume that the next IOCTL_POWER_SET command is in response to its request. Be sure to check the state specified in the IOCTL to see what state the Power Manager needs the device to assume.
Drivers for devices that support reduced power levels, such as a rotating hard drive, can manage their own internal state changes as needed, and only request transitions between device power states that the Power Manager is aware of. For example, in the case of the rotating hard drive, if the driver decides to spin down the hard drive to save power because it is idle, there is no need to call DevicePowerNotify because this transition does not correspond to a Dx transition (x=1,2, etc.)
For an example of how to use the DevicePowerNotify API, look in the DEVSAMPLE directory in the PUBLIC\COMMON\OAK\DRIVERS\PM\TEST.
Special Handling for the D3 Device Power State
Devices in the D3 Device Power State are allowed to wake the system from suspend. Wake-enabled devices may need to make the D2 state and the D3 state the same, except for enabling the wakeup feature on D3.
On the other hand, devices that do not support wakeup are still allowed to enter the D3 Device Power State, so there is no guarantee that a device in the D3 state will be able to wake the system from suspend.
For example, suppose you have a device that is not wake-enabled that supports a low power mode that generates device activity. In this case, the device is allowed to use D3 in self-management of power. If a non-wake-enabled device is in D3 and the system suspends, the device should go to D4 as it enters suspend, and return to D3 on resume.
If your device is capable of waking the system from D3, the driver should not use the DevicePowerNotify API to request the D3 state.
If a driver handles power requests for dependent child devices or client drivers, it can call the RegisterPowerRelationship API to tell the Power Manager about this relationship. This might be used, for example, by a bus driver, or by a driver that needed to act as the proxy for a device, intercepting all power IOCTLs for that device.
Another way for parent-child relationships to be handled would be for the OEM to define a class that tells the Power Manager to communicate through the proxy driver instead.
The corresponding ReleasePowerRelationship API should be called when the relationship is no longer required.
The CeSetPowerOnEvent API
In Windows CE .NET 4.1, there is a new CeSetPowerOnEvent API that allows power handlers to signal non-interrupt events during suspend/resume. This new API lets you replace the previous method of setting a flag in your power handler callback and polling for it in your Interrupt Service Thread (IST). Instead, you can call this API from your power handler to set a "non-interrupt" event during power on. Events set with this API are not checked by the kernel until it returns out of its resume code. The kernel keeps track of these event handles, and when it finishes calling all the power handlers in the system, it will go through its list of events and set them, one at a time. It is important to remember that calling this API at any time other than your XXX_PowerUp handler will not take effect until the next time the system resumes. The DEVSAMPLE example in the PUBLIC\COMMON\OAK\PM\TEST directory shows how to use the CeSetPowerOnEvent API.
PCMCIA Client Drivers Can Stay Loaded During Suspend/Resume
Beginning with Windows CE .NET 4.1, PCMCIA client drivers, including those for NDIS and file system clients, can now stay loaded during system suspend/resume, assuming that the card is not physically removed. To take advantage of this feature, set the ResetOnResume registry entry (DWORD) to 1 to indicate that you want the driver to remain loaded. The default value for this entry is 0, which indicates the driver should be unloaded on suspend. This registry entry is not new—it now applies to PCMCIA adapters also. For example:
The new power management model in Windows CE .NET incorporates APIs that allow applications to receive notifications about power events, and to impose device power requirements. This section describes the APIs that are available, along with notes about the usage of the new APIs.
There are two mechanisms by which applications can be involved in power management on Windows CE .NET: the application interface, and the notification interface. The application interface is used to set or get information about the current system and device power states, and the notification interface is used to provide notification of power events.
The GetSystemPowerState API returns the current system power state name and flags. The associated POWER_STATE_XXX flags are defined in the pm.h header file.
The GetDevicePower API returns the current power state for a device, given the device name, for example, COM1:. Beginning with Windows CE .NET 4.1, you can specify the POWER_FORCE flag when calling this API to force the Power Manager to issue an IOCTL_POWER_GET to the named device, rather than using the Power Manager's internally cached state for that device.
The SetSystemPowerState API can be used by OEM applications, for example, Control Panel applets to set the system power state to the requested value. Other applications can also call this API, but in some cases the OEM may modify the Power Manager to restrict some state transitions. When calling this API, the application either provides the name of the state it needs the system to enter, in which case the state flags are ignored, or specifies the system power state using the POWER_STATE_XXX flags as defined in pm.h. There is an optional POWER_FORCE flag that can be specified, but the interpretation of this flag is platform-dependent. Note that when you call this API, if the request sends the system into the Suspend state, the function does not return until the system resumes after the suspend. Beginning with Windows CE .NET 4.1, the default Power Manager implementation will not allow applications to initiate arbitrary system power state transitions. There is also a new feature in Windows CE .NET 4.1 that allows applications to set the system power state to its current level, which results in the Power Manager reloading the power state configuration from the registry and updating devices appropriately.
The SetDevicePower API is used to set the power state for a device. OEM applications, such as Control Panel applets, are allowed to use this API. Other applications should avoid using this API because it restricts self-management by sophisticated devices, and overrides the Power Manager's standard handling of device power states. As an alternative, applications can use the SetPowerRequirement API described in the following paragraph. To resume normal power management, you can call the SetDevicePower API with the PwrDeviceUnspecified state.
The SetPowerRequirement API can be used to request that the Power Manager maintain a given device at a specified minimum level, or floor. The default implementation of the Power Manager allows these requirements to override system power states, that is, the floor overrides the ceiling. An enhancement introduced with Windows CE .NET 4.1 allows the application to specify the POWER_FORCE flag, resulting in the requirement being enforced during system suspend. A call to the SetDevicePower API will override any requirements set by calling SetPowerRequirement.
If multiple requirements are in effect, the Power Manager chooses the highest (most power consumptive) floor. For example, if a device has both a D1 and a D2 requirement, the Power Manager will keep the device in D1. In Windows CE .NET 4.0, repeated calls to SetPowerRequirement from the same process will replace the previous setting. However, beginning with Windows CE .NET 4.1, there is no longer a limitation on the number of requirements a single process can impose on a given device; this allows multiple threads within a process to impose different requirements.
The ReleasePowerRequirement API should be called to release a previously set power requirement for a given device. You should always release the requirement as soon as possible. If the calling process exits without releasing a power requirement, the Power Manager will automatically release the requirement.
The notification interface to the Power Manager is used to allow applications and drivers to receive notifications of power events. To be able to use this feature, the application must first create a message queue, and then pass the handle to the message queue to the Power Manager when it calls the RequestPowerNotifications API. The Power Manager then delivers the notifications through the message queue, with each entry formatted as a POWER_BROADCAST structure.
The following notifications are currently supported:
- PBT_RESUME—System resuming from suspend
- PBT_POWERSTATUSCHANGE—System transitions to or from AC power
- PBT_TRANSITION—System power state change
- PBT_POWERINFOCHANGE (Windows CE .NET 4.1 and later)—Battery level information
Beginning with Windows CE .NET 4.1, the caller can elect to receive only a subset of the available notifications, rather than all of them. When the caller wants to stop receiving power notifications, it should call the StopPowerNotifications API, providing the handle returned from the previous RequestPowerNotifications call as one of the arguments.
The new features in Windows CE .NET enable you to extend power savings and battery life for embedded systems and devices. With Windows CE .NET 4.1 applications can now interface with the Power Manager, and device drivers can intelligently manage device power state that is separate from the system power state. As this article has demonstrated, OEMs can modify the Power Manager component to provide custom power handling for their platforms.
About the Authors
Lori Pape is the President and co-founder of PS Technology Corporation (http://www.pstech.com), where she provides device driver development and consulting services to hardware OEMs. She also teaches public and on-site seminars about developing device drivers for Windows CE .NET and Windows XP. Lori holds a B.A. in Math Sciences from Rice University, and has 24 years of professional experience in device driver development, operating system internals, and system architecture.
For Additional Information
For more information about Windows CE .NET, see the Windows Embedded Web site.
For online documentation and context-sensitive Help included with Windows CE .NET, see the Windows CE .NET product documentation.