⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 power.cpp

📁 SM501基于ARMV4/ARMV4I平台
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// -----------------------------------------------------------------------------
//
//  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 + -