📄 platform.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//
// This module implements a set of states defined by the MS Mobile Devices
// Division as a baseline for Pocket PC devices. OEMs may choose to customize
// this file to support the hardware specific to their platform.
//
#include <pmimpl.h>
#include <nkintr.h>
#include <extfile.h>
#include <pmpolicy.h>
#include <pwsdef.h>
typedef BOOL (WINAPI * PFN_GwesPowerDown)(void);
typedef void (WINAPI * PFN_GwesPowerUp)(BOOL);
typedef BOOL (WINAPI * PFN_ShowStartupWindow)( void );
#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 } };
HANDLE ghevGwesReady;
BOOL gfGwesReady;
INT giPreSuspendPriority;
INT giSuspendPriority;
BOOL gfPasswordOn = 0;
BOOL gfSupportPowerButtonRelease = FALSE;
BOOL gfPageOutAllModules = FALSE;
DefaultPowerStateManager *g_pPowerStateManager = NULL;
// 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 = ERROR_GEN_FAILURE;
DWORD 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);
}
dwSize = sizeof(dwSize);
if(RegQueryTypedValue(hkPM, L"PageOutAllModules", &dwValue, &dwSize, REG_DWORD) == ERROR_SUCCESS
&& dwValue!=0 )
gfPageOutAllModules = TRUE;
else
gfPageOutAllModules = FALSE;
}
// 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));
}
if(dwStatus == ERROR_SUCCESS) {
pszName = PMCLASS_DISPLAY;
pszValue = _T("Power-manageable display drivers");
dwStatus = RegSetValueEx(hkSubkey, pszName, 0, REG_SZ, (LPBYTE) pszValue,
(_tcslen(pszValue) + 1) * sizeof(*pszValue));
}
}
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));
}
// release resources
if(hkPM != NULL) RegCloseKey(hkPM);
PMLOGMSG(ZONE_INIT, (_T("-%s: returning %d\r\n"), pszFname, dwStatus));
return dwStatus;
}
// This routine performs platform-specific initialization on a device list.
// Primarily this involves determining what routines should be used to communicate
// with the class.
EXTERN_C BOOL WINAPI
PlatformDeviceListInit(PDEVICE_LIST pdl)
{
BOOL fOk = FALSE;
PDEVICE_INTERFACE pInterface;
SETFNAME(_T("PlatformDeviceListInit"));
PREFAST_DEBUGCHK(pdl != NULL);
DEBUGCHK(pdl->pGuid != NULL);
if(*pdl->pGuid == idPMDisplayDeviceClass) {
PMLOGMSG(ZONE_INIT || ZONE_PLATFORM,
(_T("%s: using display interface to access class %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\r\n"),
pszFname, pdl->pGuid->Data1, pdl->pGuid->Data2, pdl->pGuid->Data3,
(pdl->pGuid->Data4[0] << 8) + pdl->pGuid->Data4[1], pdl->pGuid->Data4[2], pdl->pGuid->Data4[3],
pdl->pGuid->Data4[4], pdl->pGuid->Data4[5], pdl->pGuid->Data4[6], pdl->pGuid->Data4[7]));
#ifndef NODISPLAYINTERFACE
// Use the display driver interface to get to the device. To remove
// display code from the link, edit or conditionally compile this code out
// of the PM.
extern DEVICE_INTERFACE gDisplayInterface; // defined in the MDD
pInterface = &gDisplayInterface;
#else // NODISPLAYINTERFACE
PMLOGMSG(ZONE_INIT || ZONE_WARN, (_T("%s: warning: display interface not supported\r\n"), pszFname));
#endif // NODISPLAYINTERFACE
} else {
// use the standard stream interface to get to the device
PMLOGMSG(ZONE_INIT || ZONE_PLATFORM,
(_T("%s: using stream interface to access class %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\r\n"),
pszFname, pdl->pGuid->Data1, pdl->pGuid->Data2, pdl->pGuid->Data3,
(pdl->pGuid->Data4[0] << 8) + pdl->pGuid->Data4[1], pdl->pGuid->Data4[2], pdl->pGuid->Data4[3],
pdl->pGuid->Data4[4], pdl->pGuid->Data4[5], pdl->pGuid->Data4[6], pdl->pGuid->Data4[7]));
extern DEVICE_INTERFACE gStreamInterface; // defined in the MDD
pInterface = &gStreamInterface;
}
// try to initialize the interface
if(pInterface != NULL) {
if(pInterface->pfnInitInterface() == FALSE) {
PMLOGMSG(ZONE_WARN, (_T("%s: warning: pfnInitInterface() failed for interface\r\n"), pszFname));
} else {
// pass back the pointer
pdl->pInterface = pInterface;
fOk = TRUE;
}
}
return fOk;
}
// This routine is responsible for mapping system power state hint
// values to known system power states that we maintain in the registry.
EXTERN_C DWORD WINAPI
PlatformMapPowerStateHint(DWORD dwHint, LPTSTR pszBuf, DWORD dwBufChars)
{
DWORD dwStatus = ERROR_FILE_NOT_FOUND;
SETFNAME(_T("PlatformMapPowerStateHint"));
if (g_pPowerStateManager) {
dwStatus = g_pPowerStateManager->PlatformMapPowerStateHint(dwHint, pszBuf, dwBufChars);
}
PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_WARN,
(_T("%s: returning %d\r\n"), pszFname, dwStatus));
return dwStatus;
}
// This routine reads and verifies system power state information from
// the registry, then updates all devices appropriately. The caller of this
// routine should hold the system power state critical section. The fInternal
// flag indicates whether the call originated within the PM or outside it.
EXTERN_C DWORD WINAPI
PlatformSetSystemPowerState(LPCTSTR pszName, BOOL fForce, BOOL fInternal)
{
DWORD dwStatus = ERROR_SUCCESS;
PSYSTEM_POWER_STATE pNewSystemPowerState = NULL;
PDEVICE_POWER_RESTRICTION pNewCeilingDx = NULL;
BOOL fDoTransition = FALSE;
INT iPreSuspendPriority = 0;
static BOOL fFirstCall = TRUE;
SETFNAME(_T("PlatformSetSystemPowerState"));
// read system power state variables and construct new lists
if (gfFileSystemsAvailable)
PmUpdateSystemPowerStatesIfChanged();
dwStatus = RegReadSystemPowerState(pszName, &pNewSystemPowerState, &pNewCeilingDx);
// did we get registry information about the new power state?
if(dwStatus == ERROR_SUCCESS) {
BOOL fSuspendSystem = FALSE;
static BOOL fWantStartupScreen = FALSE;
DWORD dwNewStateFlags = pNewSystemPowerState->dwFlags;
BOOL fPasswordOn = ((dwNewStateFlags & POWER_STATE_PASSWORD)!=0) ;
// assume we will update the system power state
fDoTransition = TRUE;
// Are we going to suspend the system as a whole?
if((dwNewStateFlags & (POWER_STATE_SUSPEND | POWER_STATE_OFF | POWER_STATE_CRITICAL | POWER_STATE_RESET)) != 0) {
fSuspendSystem = TRUE;
}
// A "critical" suspend might mean we have totally lost battery power and need
// to suspend really quickly. Depending on the platform, OEMs may be able
// to bypass driver notification entirely and rely on xxx_PowerDown() notifications
// to suspend gracefully. Or they may be able to implement a critical suspend
// kernel ioctl. This sample implementation is very generic and simply sets the
// POWER_FORCE flag, which is not used.
if(dwNewStateFlags & (POWER_STATE_CRITICAL | POWER_STATE_OFF | POWER_STATE_RESET)) {
fForce = TRUE;
}
// if everything seems ok, do the set operation
if(fDoTransition) {
POWER_BROADCAST_BUFFER pbb;
PDEVICE_LIST pdl;
BOOL fResumeSystem = FALSE;
// send out system power state change notifications
pbb.Message = PBT_TRANSITION;
pbb.Flags = pNewSystemPowerState->dwFlags;
pbb.Length = _tcslen(pNewSystemPowerState->pszName) + 1; // char count not byte count for now
if(pbb.Length > MAX_PATH) {
// truncate the system power state name -- note, we actually have MAX_PATH + 1
// characters available.
pbb.Length = MAX_PATH;
}
_tcsncpy(pbb.SystemPowerState, pNewSystemPowerState->pszName, pbb.Length);
pbb.Length *= sizeof(pbb.SystemPowerState[0]); // convert to byte count
GenerateNotifications((PPOWER_BROADCAST) &pbb);
// is GWES ready?
if(!gfGwesReady) {
if(ghevGwesReady != NULL && WaitForSingleObject(ghevGwesReady, 0) == WAIT_OBJECT_0) {
gfGwesReady = TRUE;
CloseHandle(ghevGwesReady);
ghevGwesReady = NULL;
}
}
// are we suspending?
if(fSuspendSystem && gpfnGwesPowerDown != NULL) {
// Start the process of suspending GWES
if(gfGwesReady) {
fWantStartupScreen = gpfnGwesPowerDown();
}
}
// update global system state variables
PMLOCK();
PSYSTEM_POWER_STATE pOldSystemPowerState = gpSystemPowerState;
PDEVICE_POWER_RESTRICTION pOldCeilingDx = gpCeilingDx;
if(gpSystemPowerState != NULL
&& (gpSystemPowerState->dwFlags & (POWER_STATE_SUSPEND | POWER_STATE_OFF | POWER_STATE_CRITICAL)) != 0) {
// we are exiting a suspended state
fResumeSystem = TRUE;
}
gpSystemPowerState = pNewSystemPowerState;
gpCeilingDx = pNewCeilingDx;
PMUNLOCK();
// are we suspending, resuming, or neither?
if(fSuspendSystem) {
INT iCurrentPriority;
// we're suspending; update all devices other than block devices,
// in case any of them need to access the registry or write files.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -