?? power.cpp
字號:
// -----------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// Copyright (c) 2002 Silicon Motion, Inc.
//
// Module Name: power.cpp
//
// Abstract: Power Management
//
// -----------------------------------------------------------------------------
#include "precomp.h"
#include "smi.h"
#ifdef USE_WATCHDOG
#include <pm.h>
#include <msgqueue.h>
#endif
///////////////////////////////////////////////////////////////////////////////
// The periodicity in seconds for the thread function to check if the power
// consumption can be adjusted for the chip's modules.
#define POWER_CHECK_DELAY 30
///////////////////////////////////////////////////////////////////////////////
// Power broadcast message size. The message consists of the two structures:
// POWER_BROADCAST and POWER_BROADCAST_POWER_INFO. The later is embedded into
// the first starting from SystemPowerState member.
#ifdef USE_WATCHDOG
#define MESSAGE_SIZE \
(sizeof(POWER_BROADCAST) + \
sizeof(POWER_BROADCAST_POWER_INFO) - \
sizeof(PPOWER_BROADCAST(0)->SystemPowerState))
#endif
///////////////////////////////////////////////////////////////////////////////
// Macro for printing debug messages
#if 1
// Print messages only in DEBUG mode
#define MESSAGE DEBUGMSG
#define MESSAGE_ZONE GPE_ZONE_WARNING
#else
// Force messages even in RELEASE mode
#define MESSAGE RETAILMSG
#define MESSAGE_ZONE 1
#endif
BOOL
WINAPI
GetSystemPowerStatusEx(
PSYSTEM_POWER_STATUS_EX pSystemPowerStatusEx,
BOOL fUpdate
);
///////////////////////////////////////////////////////////////////////////////
// Define to see ALL messages
//#define ENABLE_ALL_MESSAGES
#ifdef USE_WATCHDOG
///////////////////////////////////////////////////////////////////////////////
// The thread function awaits for changes in the power source type from
// AC to DC and vice versa. In the mean time if the timeout has occured
// (no change in power has been detected for a while), the function will
// check the activity for each supported module of the chip to determine
// whether the power consumption can be reduced.
DWORD WINAPI PowerManagementThread(LPVOID lpParameter)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+PowerManagementThread\r\n")));
SMI* pSMI = (SMI*)lpParameter;
while (1)
{
// Wait for a message.
MESSAGE(MESSAGE_ZONE, (TEXT("PowerManagementThread: entering WaitForSingleObject\r\n")));
DWORD dwResult = WaitForSingleObject(
pSMI->GetPMMessageQueue(), POWER_CHECK_DELAY * 1000);
if (dwResult == WAIT_OBJECT_0)
{
// Received a message.
MESSAGE(MESSAGE_ZONE, (TEXT("PowerManagementThread: received a message\r\n")));
// Init message buffer.
// Message buffer size is a size of combined structures
// POWER_BROADCAST and POWER_BROADCAST_POWER_INFO, where
// the latter is located starting from SystemPowerState member
// of the first.
BYTE MessageBuffer[MESSAGE_SIZE];
PPOWER_BROADCAST PowerBroadcast =
(PPOWER_BROADCAST)&MessageBuffer;
PPOWER_BROADCAST_POWER_INFO PowerInfo =
(PPOWER_BROADCAST_POWER_INFO)&MessageBuffer +
FIELD_OFFSET(POWER_BROADCAST, SystemPowerState);
// These're required by ReadMsgQueue.
DWORD BytesRead;
DWORD Flags;
BOOL bOk = ReadMsgQueue(
pSMI->GetPMMessageQueue(), // Queue handle.
PowerBroadcast, // Buffer pointer.
MESSAGE_SIZE, // Buffer size.
&BytesRead, // [out] number of bytes read.
0, // Don't wait, just read.
&Flags); // [out] Message flags.
if (bOk)
{
if (PowerBroadcast->Message == PBT_POWERINFOCHANGE)
{
if (pSMI->IsMonitorEnabled())
{
#if 0
// It has been decided to remove the power level adjustment
// from the PBT_POWERINFOCHANGE message and leave the power
// level management completely up to the timeout mechanism.
// This is done while pursuing two goals. First to centralize
// the control to one mechanism only and secondly, to prevent
// possible screen corruptions during the boot time noticed on
// some Fujitsu systems (03/10/04).
SYSTEM_POWER_STATUS_EX PowerStatus;
if (GetSystemPowerStatusEx(&PowerStatus, TRUE))
{
switch (PowerStatus.ACLineStatus)
{
case 0:
// DC mode.
MESSAGE(MESSAGE_ZONE, (TEXT("DC Power Mode Switch Detected.\r\n")));
if (pSMI->GetCurrentPowerState() < VGXPowerStandBy)
{
pSMI->SetVGXPowerManagement(VGXPowerReduced);
}
break;
case 1:
// AC mode.
MESSAGE(MESSAGE_ZONE, (TEXT("AC Power Mode Switch Detected.\r\n")));
if (pSMI->GetCurrentPowerState() < VGXPowerStandBy)
{
pSMI->SetVGXPowerManagement(VGXPowerOn);
}
break;
default:
MESSAGE(MESSAGE_ZONE, (TEXT("Unknown power mode: %d\r\n"), PowerStatus.ACLineStatus));
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("GetSystemPowerStatusEx failed\r\n")));
}
#endif
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("Power Monitor is currently disabled\r\n")));
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("The message is not PBT_POWERINFOCHANGE (%d)\r\n"), PowerBroadcast->Message));
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("ReadMsgQueue failed (%d)\r\n"), GetLastError()));
}
}
else if (dwResult == WAIT_TIMEOUT)
{
MESSAGE(MESSAGE_ZONE, (TEXT("Timeout has occured.\r\n")));
// Make sure the system is not in power down mode
if (pSMI->GetCurrentPowerState() < VGXPowerStandBy)
{
MESSAGE(MESSAGE_ZONE, (TEXT("Checking if the power consumption can be reduced.\r\n")));
MESSAGE(MESSAGE_ZONE, (TEXT("Current tick count = %u\r\n"), pSMI->GetTickCountSafe()));
MESSAGE(MESSAGE_ZONE, (TEXT("Ticks to Minimal = %u\r\n"), pSMI->GetTicksToMinimal()));
MESSAGE(MESSAGE_ZONE, (TEXT("Ticks to Reduced = %u\r\n"), pSMI->GetTicksToReduced()));
// Check whether the monitor is enabled
if (pSMI->IsMonitorEnabled())
{
// Check if we can switch to minimal mode
DWORD Idle = pSMI->GetTicksSince(pSMI->GetReducedLastRequested());
MESSAGE(MESSAGE_ZONE, (TEXT("Checking for Minimal mode:\r\n")));
MESSAGE(MESSAGE_ZONE, (TEXT("* Tick count when Reduced was last requested ... : %u\r\n"), pSMI->GetReducedLastRequested()));
MESSAGE(MESSAGE_ZONE, (TEXT("* Ticks since Reduced last requested ........... : %u\r\n"), Idle));
if (Idle >= pSMI->GetTicksToMinimal())
{
if (pSMI->GetCurrentPowerState() < VGXPowerMinimal)
{
pSMI->SetVGXPowerManagement(VGXPowerMinimal);
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("* The current power mode is slower or equal to the requested:\r\n")));
MESSAGE(MESSAGE_ZONE, (TEXT(" Current: %d\r\n"), pSMI->GetCurrentPowerState()));
MESSAGE(MESSAGE_ZONE, (TEXT(" Requested: %d\r\n"), VGXPowerMinimal));
}
}
else
{
// Check if we can switch to reduced mode
Idle = pSMI->GetTicksSince(pSMI->GetPowerOnLastRequested());
MESSAGE(MESSAGE_ZONE, (TEXT("Checking for Reduced mode:\r\n")));
MESSAGE(MESSAGE_ZONE, (TEXT("* Tick count when Full Power mode was last requested ... : %u\r\n"), pSMI->GetPowerOnLastRequested()));
MESSAGE(MESSAGE_ZONE, (TEXT("* Ticks since Full Power mode last requested ........... : %u\r\n"), Idle));
if (Idle >= pSMI->GetTicksToReduced())
{
if (pSMI->GetCurrentPowerState() < VGXPowerReduced)
{
MESSAGE(MESSAGE_ZONE, (TEXT("* SWITCHING...\r\n")));
pSMI->SetVGXPowerManagement(VGXPowerReduced);
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("* The current power mode is slower or equal to the requested:\r\n")));
MESSAGE(MESSAGE_ZONE, (TEXT(" Current: %d\r\n"), pSMI->GetCurrentPowerState()));
MESSAGE(MESSAGE_ZONE, (TEXT(" Requested: %d\r\n"), VGXPowerReduced));
}
}
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("The Power Monitor is disabled.\r\n")));
}
// Check if we can switch off any of the managed devices
for (DWORD i = 0; i < VGXPM_MODULE_COUNT; i++)
{
// Check whether the monitor is enabled on the module
BOOL bEnabled;
pSMI->GetModuleMonitorEnabled((VGXPM_MODULES)i, bEnabled);
if (bEnabled)
{
// Get the amount of ticks of the last call
DWORD LastCallTickCount;
pSMI->GetLastCallTickCount((VGXPM_MODULES)i, LastCallTickCount);
// Calculate the idle time
DWORD Idle = pSMI->GetTicksSince(LastCallTickCount);
// Get the amount of ticks before power down
DWORD TicksToPowerDown;
pSMI->GetTicksToPowerDown((VGXPM_MODULES)i, TicksToPowerDown);
MESSAGE(MESSAGE_ZONE, (TEXT("Module %u\r\n"), i));
MESSAGE(MESSAGE_ZONE, (TEXT("* Idle = %u, TicksToPowerDown = %u\r\n"), Idle, TicksToPowerDown));
// Check if it's time to switch off the power
if (Idle >= TicksToPowerDown)
{
// Get the current module power state
VGX_POWER_STATE PowerState;
pSMI->GetModulePower((VGXPM_MODULES)i, PowerState);
if (PowerState != VGXPowerOff)
{
MESSAGE(MESSAGE_ZONE, (TEXT("* SWITCHING OFF\r\n")));
pSMI->SetModulePower((VGXPM_MODULES)i, VGXPowerOff);
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("* The module is already off\r\n")));
}
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("The Module Power Monitor is disabled for module #%u\r\n"), i));
}
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("The system is in power down mode, the timeout is ignored.\r\n")));
}
}
}
return 0;
}
#endif
///////////////////////////////////////////////////////////////////////////////
// Returns the tick count.
DWORD SMI::GetTickCountSafe()
{
static DWORD LastTickCount = 0;
if (m_bInPowerHandler)
{
// We are currently called in PowerHandler's context, where we cannot
// call certain APIs, otherwise exception will be raised. Advance the
// current tick counter so that internal time loops won't hang.
LastTickCount++;
}
else
{
LastTickCount = GetTickCount();
}
return LastTickCount;
}
///////////////////////////////////////////////////////////////////////////////
// Returns the amount of ticks since the specified time mark.
DWORD SMI::GetTicksSince(DWORD Mark)
{
DWORD CurrentCount = GetTickCountSafe();
return (Mark <= CurrentCount)?
CurrentCount - Mark : 0xFFFFFFFF - (Mark - CurrentCount - 1);
}
///////////////////////////////////////////////////////////////////////////////
// This function is called in response to GETPOWERMANAGEMENT message.
DWORD SMI::HandleGetPowerManagement(DWORD cjIn, PVOID pvIn, DWORD cjOut, PVOID pvOut)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::HandleGetPowerManagement\r\n")));
DWORD dwResult;
if ((cjOut >= sizeof(VIDEO_POWER_MANAGEMENT)) && (pvOut != NULL))
{
PVIDEO_POWER_MANAGEMENT pParam;
pParam = (PVIDEO_POWER_MANAGEMENT)pvOut;
pParam->Length = sizeof(VIDEO_POWER_MANAGEMENT);
pParam->DPMSVersion = 0;
pParam->PowerState = GetCurrentPowerState();
dwResult = VGXPM_RET_SUCCESS;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
dwResult = VGXPM_RET_INVALID_PARAMETER;
}
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::HandleGetPowerManagement\r\n")));
return dwResult;
}
///////////////////////////////////////////////////////////////////////////////
// This function is called in response to SETPOWERMANAGEMENT message.
DWORD SMI::HandleSetPowerManagement(DWORD cjIn, PVOID pvIn, DWORD cjOut, PVOID pvOut)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::HandleSetPowerManagement\r\n")));
DWORD dwResult;
if ((cjIn >= sizeof(VIDEO_POWER_MANAGEMENT)) && (pvIn != NULL))
{
PVIDEO_POWER_MANAGEMENT pParam;
pParam = (PVIDEO_POWER_MANAGEMENT)pvIn;
SetPowerManagement((VIDEO_POWER_STATE)pParam->PowerState);
dwResult = VGXPM_RET_SUCCESS;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
dwResult = VGXPM_RET_INVALID_PARAMETER;
}
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::HandleSetPowerManagement\r\n")));
return dwResult;
}
///////////////////////////////////////////////////////////////////////////////
// SMI Power Management API external entry point.
DWORD SMI::HandleSMIPowerManagement(DWORD cjIn, PVOID pvIn, DWORD cjOut, PVOID pvOut)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::HandleSMIPowerManagement\r\n")));
DWORD dwResult = VGXPM_RET_INVALID_PARAMETER;
// Make sure the input structure is valid
if ((cjIn >= sizeof(VGXPM_STRUCT)) && (pvIn != NULL))
{
PVGXPM_STRUCT pIn = (PVGXPM_STRUCT)pvIn;
switch (pIn->Command)
{
case VGXPMCMD_INIT:
if ((cjIn == sizeof(VGXPM_STRUCT)) &&
(cjOut == 0) && (pvOut == NULL))
{
dwResult = StartPowerThread();
}
else
{
MESSAGE(MESSAGE_ZONE,
(TEXT("HandleSMIPowerManagement: invalid VGXPMCMD_INIT parameters\r\n")));
}
break;
case VGXPMCMD_SET_MONITOR:
if ((cjIn == sizeof(VGXPM_MONITOR_STRUCT)) &&
(cjOut == 0) && (pvOut == NULL))
{
PVGXPM_MONITOR_STRUCT pSetMonitor = (PVGXPM_MONITOR_STRUCT)pvIn;
SetMonitorEnabled(pSetMonitor->bMonitorEnabled);
dwResult = VGXPM_RET_SUCCESS;
}
else
{
MESSAGE(MESSAGE_ZONE,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -