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

📄 power.cpp

📁 Sm501 VGA芯片wince下驱动代码
💻 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


///////////////////////////////////////////////////////////////////////////////
// Extra functions for clock switching.

//#define RESET_DRAM_CONTROLLER
//#define CHANGE_FIFO_PRIORITIES


///////////////////////////////////////////////////////////////////////////////
// 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

extern DWORD g_SetPowerCEPC;   // 0=Set power mode for non-X86 systems(default), 1=for X86 compatible systems


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")));

			// Check for the reset request
			if (pSMI->IsPowerResetPending())
			{
				pSMI->ResetPowerManagement();
				continue;
			}

			// Make sure the system is not in power down mode
			if (pSMI->GetCurrentPowerState() >= VGXPowerStandBy)
			{
				MESSAGE(MESSAGE_ZONE, (TEXT("The system is in power down mode, the timeout is ignored.\r\n")));
				continue;
			}

			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));
				}
			}
		}
	}

	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)
{
	return GetTickCountSafe() - Mark;
}


///////////////////////////////////////////////////////////////////////////////
// Wait for the specified number of ticks.

VOID SMI::WaitForTicks(DWORD Count)
{
	DWORD start = GetTickCountSafe();
	while (TRUE)
	{
		DWORD elapsed = GetTicksSince(start);
		if (elapsed >= Count)
			break;
	}
}


///////////////////////////////////////////////////////////////////////////////
// This function is called in response to GETPOWERMANAGEMENT message.

BOOL SMI::IsPowerResetPending()
{
	return m_bResetPowerManagement;
}

VOID SMI::PowerResetDone()
{
	m_bResetPowerManagement = FALSE;
}

VOID SMI::InitiatePowerReset()
{
	m_bResetPowerManagement = TRUE;
}


///////////////////////////////////////////////////////////////////////////////
// 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)
		{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -