📄 platform.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// This module contains platform-specific code that may be modified by an OEM
// as they customize the Power Manager for a particular device. This sample
// platform implementation can be used to run the PM in an "active" or a
// "passive" mode. In the active mode, the PM monitors system events and
// decides when to update the system power state. Its goal is to put the
// system into progressively lower system power states during periods of
// inactivity. In passive mode, the PM doesn't update system power states
// on its own -- instead, it expects external software to initiate updates.
// This mode is functionally backwards compatible with older versions of CE
// in which GWES makes all the decisions about when to suspend the system.
//
// The PM decides at run time whether to operate in active or passive mode
// based on registry settings (see the implementation of
// PlatformPMActivelyManagesPower()). When OEMs customize the PM for their
// platform they should choose one of these modes.
//
// In active mode, this sample code implements a simple state machine that
// maps events occurring on the device to system power state transitions
// that the Power Manager understands. Note that, unlike in passive mode,
// the PM must have some built-in understanding of which power states are
// appropriate for which events. This is appropriate, since only OEMs
// should be defining system power states.
//
// States in the state machine do not have a 1-to-1 correspondence with
// system power states defined in the registry. The general model of operation
// is that system level events are mapped into PLATFORM_ACTIVITY_EVENT events
// and fed into the state machine. The state machine uses events to update
// its own states, defined as PLATFORM_ACTIVITY_STATE states. Each transition
// in the state machine may be accompanied by a system power state transition
// and/or an update of the timeout associated with the platform activity state.
//
// This sample implementation only understands a few system power states. It is
// possible, and may be desirable, for OEMs to define different sets of power
// states based on AC power vs Battery, in cradle or out of cradle, etc. In this
// case the OEM will need to update the state machine code and its inputs
// appropriately.
//
#include <pmimpl.h>
#include <nkintr.h>
#include <extfile.h>
#include <pmpolicy.h>
// This typedef describes the system activity states. These are independent of
// factors such as AC power vs. battery, in cradle or not, etc. OEMs may choose
// to add their own activity states if they customize this module.
typedef enum {
UserActive, UserInactive,
UserIdle,
SystemActive, SystemInactive,
Suspend
} PLATFORM_ACTIVITY_STATE, *PPLATFORM_ACTIVITY_STATE;
// This typedef describes activity events such as user activity or inactivity,
// power status changes, etc. OEMs may choose to factor other events into their
// system power state transition decisions.
typedef enum {
NoActivity,
UserActivity,
UserInactivity,
SystemActivity,
SystemInactivity,
Timeout,
RestartTimeouts,
PowerSourceChange,
Resume
} PLATFORM_ACTIVITY_EVENT, *PPLATFORM_ACTIVITY_EVENT;
typedef BOOL (WINAPI * PFN_GwesPowerDown)(void);
typedef void (WINAPI * PFN_GwesPowerUp)(BOOL);
typedef BOOL (WINAPI * PFN_ShowStartupWindow)( void );
// platform-specific default values
#define DEF_TIMEOUTTOUSERIDLE 60 // in seconds, 0 to disable
#define DEF_TIMEOUTTOSYSTEMIDLE 300 // in seconds, 0 to disable
#define DEF_TIMEOUTTOSUSPEND 600 // in seconds, 0 to disable
#define MAXACTIVITYTIMEOUT (0xFFFFFFFF / 1000) // in seconds
// gwes suspend/resume functions
PFN_GwesPowerDown gpfnGwesPowerDown = NULL;
PFN_GwesPowerUp gpfnGwesPowerUp = NULL;
PFN_ShowStartupWindow gpfnShowStartupWindow = NULL;
// this variable is protected by the system power state critical section
BOOL gfSystemSuspended = FALSE;
BOOL gfFileSystemsAvailable = TRUE;
GUID idBlockDevices = {0x8DD679CE, 0x8AB4, 0x43c8, { 0xA1, 0x4A, 0xEA, 0x49, 0x63, 0xFA, 0xA7, 0x15 } };
// activity timer variables
HANDLE ghevReloadActivityTimeouts;
HANDLE ghevRestartTimers;
HANDLE ghevSignalUserActivity;
HANDLE ghevUserActive;
HANDLE ghevUserInactive;
HANDLE ghevSignalSystemActivity;
HANDLE ghevSystemActive;
HANDLE ghevSystemInactive;
HANDLE ghevGwesReady;
BOOL gfGwesReady;
DWORD gdwACTimeoutToUserIdle;
DWORD gdwACTimeoutToSystemIdle;
DWORD gdwACTimeoutToSuspend;
DWORD gdwBattTimeoutToUserIdle;
DWORD gdwBattTimeoutToSystemIdle;
DWORD gdwBattTimeoutToSuspend;
DWORD gdwStateTimeLeft = INFINITE;
PLATFORM_ACTIVITY_STATE gActivityState = UserActive;
BOOL gfActiveManagement;
HANDLE ghevBootPhase2;
INT giPreSuspendPriority;
INT giSuspendPriority;
BOOL gfPasswordOn = FALSE;
BOOL gfSupportPowerButtonRelease = FALSE;
// need "C" linkage for compatibility with C language PDD implementations
extern "C" {
POWER_BROADCAST_POWER_INFO gSystemPowerStatus;
};
// This routine is called to check the consistency of the system's power
// management registry settings. It is called during during power manager
// initialization. If no registry settings are found, OEMs can use this
// routine to set them up. The routine returns FALSE if some fatal error
// is discovered and the registry is unusable. This will halt PM
// initialization. If the registry is OK (or can be initialized/repaired)
// this routine returns ERROR_SUCCESS, otherwise it returns an error code.
EXTERN_C DWORD WINAPI
PlatformValidatePMRegistry(VOID)
{
HKEY hkPM = NULL, hkSubkey;
LPTSTR pszSubKey;
DWORD dwStatus, dwDisposition;
SETFNAME(_T("PlatformValidatePMRegistry"));
PMLOGMSG(ZONE_INIT, (_T("+%s\r\n"), pszFname));
// open the PM registry key
dwStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, PWRMGR_REG_KEY, 0, NULL, 0, 0, NULL,
&hkPM, &dwDisposition);
if(dwStatus != ERROR_SUCCESS) {
PMLOGMSG(ZONE_ERROR, (_T("%s: can't open '%s', error is %d\r\n"), pszFname,
PWRMGR_REG_KEY, dwStatus));
}
if (dwStatus== ERROR_SUCCESS && dwDisposition != REG_CREATED_NEW_KEY ) { // Exit Key.
DWORD dwValue = 0;
DWORD dwSize = sizeof(DWORD);
if (RegQueryTypedValue(hkPM, PM_SUPPORT_PB_RELEASE, &dwValue, &dwSize, REG_DWORD)==ERROR_SUCCESS) {
gfSupportPowerButtonRelease = (dwValue!=0);
}
}
// verify the On system state
if(dwStatus == ERROR_SUCCESS) {
pszSubKey = _T("State\\On");
dwStatus = RegCreateKeyEx(hkPM, pszSubKey, 0, NULL, 0, 0, NULL, &hkSubkey,
&dwDisposition);
if(dwStatus == ERROR_SUCCESS) {
if(dwDisposition == REG_CREATED_NEW_KEY) {
// populate the default value of the key with the default device power state
DWORD dwValue = 0; // D0
dwStatus = RegSetValueEx(hkSubkey, NULL, 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
// write the flags value
if(dwStatus == ERROR_SUCCESS) {
dwValue = POWER_STATE_ON;
dwStatus = RegSetValueEx(hkSubkey, _T("Flags"), 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
}
}
RegCloseKey(hkSubkey);
}
PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_ERROR,
(_T("%s: error %d while creating or writing values in '%s\\%s'\r\n"), pszFname, dwStatus,
PWRMGR_REG_KEY, pszSubKey));
}
// verify the UserIdle system state
if(dwStatus == ERROR_SUCCESS) {
pszSubKey = _T("State\\UserIdle");
dwStatus = RegCreateKeyEx(hkPM, pszSubKey, 0, NULL, 0, 0, NULL, &hkSubkey,
&dwDisposition);
if(dwStatus == ERROR_SUCCESS) {
if(dwDisposition == REG_CREATED_NEW_KEY) {
// populate the default value of the key with the default device power state
DWORD dwValue = 1; // D1
dwStatus = RegSetValueEx(hkSubkey, NULL, 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
// write the flags value
if(dwStatus == ERROR_SUCCESS) {
dwValue = 0;
dwStatus = RegSetValueEx(hkSubkey, _T("Flags"), 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
}
}
RegCloseKey(hkSubkey);
}
PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_ERROR,
(_T("%s: error %d while creating or writing values in '%s\\%s'\r\n"), pszFname, dwStatus,
PWRMGR_REG_KEY, pszSubKey));
}
// verify the SystemIdle system state
if(dwStatus == ERROR_SUCCESS) {
pszSubKey = _T("State\\SystemIdle");
dwStatus = RegCreateKeyEx(hkPM, pszSubKey, 0, NULL, 0, 0, NULL, &hkSubkey,
&dwDisposition);
if(dwStatus == ERROR_SUCCESS) {
if(dwDisposition == REG_CREATED_NEW_KEY) {
// populate the default value of the key with the default device power state
DWORD dwValue = 2; // D2
dwStatus = RegSetValueEx(hkSubkey, NULL, 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
// write the flags value
if(dwStatus == ERROR_SUCCESS) {
dwValue = 0;
dwStatus = RegSetValueEx(hkSubkey, _T("Flags"), 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
}
}
RegCloseKey(hkSubkey);
}
PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_ERROR,
(_T("%s: error %d while creating or writing values in '%s\\%s'\r\n"), pszFname, dwStatus,
PWRMGR_REG_KEY, pszSubKey));
}
// verify the Suspend system state
if(dwStatus == ERROR_SUCCESS) {
pszSubKey = _T("State\\Suspend");
dwStatus = RegCreateKeyEx(hkPM, pszSubKey, 0, NULL, 0, 0, NULL, &hkSubkey,
&dwDisposition);
if(dwStatus == ERROR_SUCCESS) {
if(dwDisposition == REG_CREATED_NEW_KEY) {
// populate the default value of the key with the default device power state
DWORD dwValue = 3; // D3
dwStatus = RegSetValueEx(hkSubkey, NULL, 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
// write the flags value
if(dwStatus == ERROR_SUCCESS) {
dwValue = POWER_STATE_SUSPEND;
dwStatus = RegSetValueEx(hkSubkey, _T("Flags"), 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
}
}
RegCloseKey(hkSubkey);
}
PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_ERROR,
(_T("%s: error %d while creating or writing values in '%s\\%s'\r\n"), pszFname, dwStatus,
PWRMGR_REG_KEY, pszSubKey));
}
// verify interface guids
if(dwStatus == ERROR_SUCCESS) {
pszSubKey = _T("Interfaces");
dwStatus = RegCreateKeyEx(hkPM, pszSubKey, 0, NULL, 0, 0, NULL, &hkSubkey,
&dwDisposition);
if(dwStatus == ERROR_SUCCESS) {
if(dwDisposition == REG_CREATED_NEW_KEY) {
LPTSTR pszName = PMCLASS_GENERIC_DEVICE;
LPTSTR pszValue = _T("Generic power-manageable devices");
dwStatus = RegSetValueEx(hkSubkey, pszName, 0, REG_SZ, (LPBYTE) pszValue,
(_tcslen(pszValue) + 1) * sizeof(*pszValue));
if(dwStatus == ERROR_SUCCESS) {
pszName = PMCLASS_BLOCK_DEVICE;
pszValue = _T("Power-manageable block devices");
dwStatus = RegSetValueEx(hkSubkey, pszName, 0, REG_SZ, (LPBYTE) pszValue,
(_tcslen(pszValue) + 1) * sizeof(*pszValue));
}
}
RegCloseKey(hkSubkey);
}
PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_ERROR,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -