emulator/emulatorbsp/specific/variant.cpp
changeset 0 cec860690d41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emulator/emulatorbsp/specific/variant.cpp	Tue Feb 02 01:39:10 2010 +0200
@@ -0,0 +1,748 @@
+// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// wins\specific\variant.cpp
+// 
+//
+
+#include "variant.h"
+#include "mconf.h"
+#include <kernel/kern_priv.h>
+#include <stdlib.h>
+#include <property.h>
+#include <emulator.h>
+
+const TInt KDefaultRam = 63;				// 63MB default internal RAM
+const TInt KUnlimitedRam = 0x400;			// 1GB ~= unlimited memory
+const TInt KDefaultRamDrive = 0x400000;		// 4MB default RAM drive limit
+
+_LIT(KLitWins,"Wins");
+
+GLDEF_D Wins TheVariant;
+
+GLDEF_D TActualMachineConfig TheConfig;
+
+EXPORT_C Asic* VariantInitialise(TBool aRunExe)
+	{
+	return TheVariant.Init(aRunExe) == KErrNone ? &TheVariant : NULL;
+	}
+
+void AsicInitialise()
+	{
+	}
+
+class DWinsPowerController : public DPowerController
+	{
+public: // from DPowerComtroller
+	void CpuIdle();
+	void EnableWakeupEvents();
+	void AbsoluteTimerExpired();
+	void DisableWakeupEvents();
+	void PowerDown(TTimeK aWakeupTime);
+public:
+	static DWinsPowerController* New();
+	void AssertWakeupSignal();
+	void WakeupEvent();
+private:
+	HANDLE	iStandbySem;
+	TUint	iStandby;
+	TBool	iWakeupSignal;
+	};
+
+Wins::Wins()
+	:iUi(0), iRealCpuSpeed(0), iCpuSpeed(0),
+	iDebugOutput(INVALID_HANDLE_VALUE), iLogTimeStamp(ETrue),
+	iPurgedImages(EFalse), iPowerController(0), iLogToDebugger(EFalse),
+	iLogToFile(ETrue)
+	{}
+
+TInt Wins::Init(TBool aRunExe)
+	{
+	TInt r = InitProperties(aRunExe);
+	if (r == KErrNone)
+		{
+		iProperties.GetInt("LogTimeStamp",iLogTimeStamp);
+		TInt logThreadId=ETrue;
+		iProperties.GetInt("LogThreadId",logThreadId);
+		TInt cpu=NThread::ECpuSingle;
+		iProperties.GetInt("HostCPU",cpu);
+		NThread::SetProperties(logThreadId,cpu);
+		iProperties.GetInt("LogToDebugger",iLogToDebugger);
+		iProperties.GetInt("LogToFile",iLogToFile);
+
+		TInt mask;
+		Kern::SuperPage().iDebugMask[0] = DebugMask();  // get int or text mask value
+		// check to see if DebugMask0 was used instead of DebugMask
+		if ( (iProperties.GetInt("DebugMask", mask) != KErrNone) &&
+			 (iProperties.GetInt("DebugMask0", mask) == KErrNone) )
+			Kern::SuperPage().iDebugMask[0] = ((iProperties.GetInt("DebugMask0", mask) == KErrNone) ? mask : 0);
+			
+		// only int entries are supported for DebugMasks 1-7
+		Kern::SuperPage().iDebugMask[1] = ((iProperties.GetInt("DebugMask1", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iDebugMask[2] = ((iProperties.GetInt("DebugMask2", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iDebugMask[3] = ((iProperties.GetInt("DebugMask3", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iDebugMask[4] = ((iProperties.GetInt("DebugMask4", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iDebugMask[5] = ((iProperties.GetInt("DebugMask5", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iDebugMask[6] = ((iProperties.GetInt("DebugMask6", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iDebugMask[7] = ((iProperties.GetInt("DebugMask7", mask) == KErrNone) ? mask : 0);
+
+		// initial values for fast trace...
+		Kern::SuperPage().iInitialBTraceFilter[0] = ((iProperties.GetInt("BTrace0", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[1] = ((iProperties.GetInt("BTrace1", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[2] = ((iProperties.GetInt("BTrace2", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[3] = ((iProperties.GetInt("BTrace3", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[4] = ((iProperties.GetInt("BTrace4", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[5] = ((iProperties.GetInt("BTrace5", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[6] = ((iProperties.GetInt("BTrace6", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceFilter[7] = ((iProperties.GetInt("BTrace7", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceBuffer = ((iProperties.GetInt("BTraceBuffer", mask) == KErrNone) ? mask : 0);
+		Kern::SuperPage().iInitialBTraceMode = ((iProperties.GetInt("BTraceMode", mask) == KErrNone) ? mask : 0);
+
+		Kern::SuperPage().SetKernelConfigFlags(KernelConfigFlags());
+
+		SCapabilitySet caps;
+		DisabledCapabilities(caps);
+		memcpy(&Kern::SuperPage().iDisabledCapabilities,&caps,sizeof(caps));
+		}
+	CalibrateCpuSpeed();
+	return r;
+	}
+
+inline void Wins::InstallUi(DWinsUiBase& aUi)
+	{iUi = &aUi;}
+
+void Wins::Init1()
+	{
+	__KTRACE_OPT(KBOOT,Kern::Printf("Wins::Init1()"));
+
+	TInt tickperiod = WinsTimer::EDefaultPeriod;
+	iProperties.GetInt("TimerResolution",tickperiod);
+	iTimer.Init(tickperiod);
+	TUint speed;
+	if (iProperties.GetInt("CPUSpeed", (TInt&)speed) == KErrNone)
+		SetCpuSpeed(speed);
+	}
+
+static TInt emulatorHal(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
+	{
+	return ((Wins*)aPtr)->EmulatorHal(aFunction, a1, a2);
+	}
+
+void Wins::Init3()
+//
+// Initialise timer tick and add emulator hal function
+//
+	{
+	__KTRACE_OPT(KBOOT,Kern::Printf("Wins::Init3()"));
+
+	Kern::AddHalEntry(EHalGroupEmulator,&emulatorHal,this);
+
+	iPowerController = DWinsPowerController::New();
+	if (iPowerController == 0)
+		__PM_PANIC("Can't create 'DWinsPowerController'");
+
+	iTimer.Enable();
+	}
+
+void Wins::AddressInfo(SAddressInfo& aInfo)
+	{
+	TInt megabytes = KDefaultRam;
+	iProperties.GetInt("MegabytesOfFreeMemory", megabytes);
+	if (megabytes == 0)
+		megabytes = KUnlimitedRam;
+	aInfo.iTotalRamSize = megabytes << 20;
+//
+	TInt ramdisk = KDefaultRamDrive;
+	iProperties.GetInt("RamDriveMaxSize", ramdisk);
+	aInfo.iRamDriveMaxSize = ramdisk;
+	}
+
+void Wins::PurgeImages()
+//
+// Use the idle thread to clean up remnants of the emulator from the image path
+//
+	{
+	char path[KMaxFileName+1];
+
+	const char* imgPath=0;
+	iProperties.GetString("EmulatorImagePath", imgPath);
+	strcpy(path, imgPath);
+	char* name = path +strlen(path);
+	strcpy(name,"*");
+
+	Emulator::Lock();
+
+	WIN32_FIND_DATAA fdata;
+	HANDLE finder = FindFirstFileA(path, &fdata);
+	if (finder != INVALID_HANDLE_VALUE)
+		{
+		do
+			{
+			if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+				{
+				strcpy(name, fdata.cFileName);
+				DeleteFileA(path);
+				}
+			} while (FindNextFileA(finder, &fdata));
+		FindClose(finder);
+		}
+
+	Emulator::Unlock();
+	}
+
+void Wins::Idle()
+//
+// Use the win32 NKern idle function
+//
+	{
+	iTimer.SetIdleThread();
+	if (!iPurgedImages)
+		{
+		PurgeImages();
+		iPurgedImages = ETrue;
+		}
+	NThread::Idle();
+	}
+
+TInt Wins::MsTickPeriod()
+//
+// Provide the 'millisecond' timer tick period in microseconds
+//
+	{
+	return 1000 * iTimer.Period();
+	}
+
+TInt Wins::SystemTimeInSecondsFrom2000(TInt& aTime)
+	{
+	aTime = iTimer.SystemTime();
+	__KTRACE_OPT(KHARDWARE,Kern::Printf("RTC READ: %d",aTime));
+	return KErrNone;
+	}
+
+TInt Wins::SetSystemTimeInSecondsFrom2000(TInt aTime)
+// 
+// Set the emulator time. We must not change the Win32 time so
+// we just adjust the offset value to account for the difference
+//
+	{
+	__KTRACE_OPT(KHARDWARE,Kern::Printf("Set RTC: %d",aTime));
+	iTimer.SetSystemTime(aTime);
+	return KErrNone;
+	}
+
+TInt Wins::VariantHal(TInt aFunction, TAny* a1, TAny* /*a2*/)
+	{
+	TInt r=KErrNone;
+	switch(aFunction)
+		{
+		case EVariantHalVariantInfo:
+			{
+			TVariantInfoV01Buf infoBuf;
+			TVariantInfoV01& info=infoBuf();
+
+//			info.iRomVersion=TVersion(KRomMajorVersionNumber,KRomMinorVersionNumber,KRomBuildVersionNumber);
+			info.iMachineUniqueId=0;
+			info.iLedCapabilities=0x0;
+			info.iProcessorClockInKHz=iCpuSpeed ? iCpuSpeed*1000 : 1;
+			info.iSpeedFactor=0;
+			if (iUi)
+				iUi->Info(info);
+
+			Kern::InfoCopy(*(TDes8*)a1,infoBuf);
+			break;
+			}
+
+		case EVariantHalCustomRestartReason:
+			{
+			//This will take value from c:\data\epoc.ini.
+			TInt x = Property::GetInt("CustomRestartReason");    
+			kumemput32(a1, &x, sizeof(TInt));
+			}
+			break;
+
+		case EVariantHalCustomRestart:
+			{
+			if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EVariantHalCustomRestart")))
+				return KErrPermissionDenied;
+			//This will only shut down epoc as Custom Restart Reason is not supported on wins.
+			Kern::Restart((TInt)a1);
+			break;
+			}
+
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+
+TPtr8 Wins::MachineConfiguration()
+	{
+	return TPckg<TActualMachineConfig>(TheConfig);
+	}
+
+void Wins::CalibrateCpuSpeed()
+//
+// calculate approx. CPU speed in MHz, 0 if we can't tell
+//
+	{
+    TInt cycleCount =200*1000*20;   //take 20ms at 20MHz
+    
+    // This loop will double the cyclecount until the difference is non-zero.
+    FOREVER
+    	{
+      	if (cycleCount > (KMaxTUint / 2))
+    		{
+    		break;
+    		}
+    
+		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+		LARGE_INTEGER start;
+		if (QueryPerformanceCounter(&start))
+    		{
+	   		__asm mov eax, cycleCount
+ 	noploop: 
+ 			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm dec eax
+			__asm sub eax, 2
+			__asm jnz noploop
+			//
+			LARGE_INTEGER end;
+			QueryPerformanceCounter(&end);
+			LARGE_INTEGER f;
+			QueryPerformanceFrequency(&f);
+			
+			TInt64 diff = (end.QuadPart - start.QuadPart);
+	    	if(diff!=0)
+	    		{
+				TInt64 hz = (TInt64(cycleCount) / 1000000) * (f.QuadPart / diff);
+				iRealCpuSpeed = (TUint)(hz);
+				break;
+		     	}
+  	  	    }
+    	cycleCount *= 2;  // Double the count!!
+ 		}
+    
+   	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+	}
+
+TInt Wins::SetCpuSpeed(TUint aSpeed)
+	{
+	if (iRealCpuSpeed == 0)
+		return KErrNotSupported;	// don't know the real CPUSpeed
+
+	if (IsDebuggerPresent())
+		return KErrGeneral;			// nobbling not avaliable when debugging
+
+	if (aSpeed == 0)
+		aSpeed = iRealCpuSpeed;		// reset to maximum
+	else if (aSpeed > iRealCpuSpeed)
+		aSpeed = iRealCpuSpeed;
+	else if (aSpeed * 20u  < iRealCpuSpeed)
+		aSpeed = (iRealCpuSpeed + 19u) / 20u;
+
+	__KTRACE_OPT(KHARDWARE,Kern::Printf("Set CPUSpeed: %d",aSpeed));
+	iCpuSpeed = aSpeed;
+
+	// calculate CPU time to nobble in parts-per-million
+	TUint nobble = ((iRealCpuSpeed - aSpeed) * 1000000u) / iRealCpuSpeed;
+	iTimer.Nobble(nobble);
+	return KErrNone;
+	}
+
+HANDLE Wins::DebugOutput()
+//
+// Return a handle to the trace file, creating the file if required.
+//
+// The log file name can be specified by a property or environment
+// variable called 'EmulatorLog', otherwise it defaults to 
+// 'epocwind.out' in the temporary directory.
+//
+	{
+	HANDLE file = iDebugOutput;
+	if (file == INVALID_HANDLE_VALUE)
+		{
+		CHAR debugfile[MAX_PATH];
+		const char* logpath;
+		if (iProperties.GetString("EmulatorLog",logpath)==KErrNone)
+			strcpy(debugfile,logpath);
+		else
+			{
+			DWORD len = GetEnvironmentVariableA("EmulatorLog", debugfile, MAX_PATH);
+			debugfile[len]=0;
+			if (len == 0)
+				{
+				len=GetTempPathA(MAX_PATH,debugfile);
+				strcpy(debugfile+len,"epocwind.out");	// EPOC WINS DEBUG output file
+				}
+			}
+		file=CreateFileA(debugfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
+		if (file!=INVALID_HANDLE_VALUE)
+			{
+			SetFilePointer(file, NULL, NULL, FILE_END);
+			iDebugOutput = file;
+			}
+		}
+	return file;
+	}
+
+const TInt MaxOutputMsg = 599;
+
+void Wins::EarlyLogging(const char* aMessage1,const char* aMessage2)
+	{
+	char message[MaxOutputMsg+3];
+	TInt len = min(strlen(aMessage1), MaxOutputMsg);
+	memcpy(message,aMessage1,len);
+	if(aMessage2)
+		{
+		TInt len2 = min((TInt)strlen(aMessage2), MaxOutputMsg-len);
+		memcpy(message+len,aMessage2,len2);
+		len+=len2;
+		}
+	message[len++] = '\r';
+	message[len++] = '\n';
+	message[len] = 0;
+
+	if (iLogToFile)
+		{
+		DWORD bytes;
+		WriteFile(DebugOutput(), message, len, &bytes, NULL);
+		}
+	if (iLogToDebugger)
+		{
+		OutputDebugStringA(message);
+		}
+	}
+
+void Wins::DebugPrint(const TDesC8& aDes)
+//
+// Send the string to the debug output (Win32 debug trace) and trace file
+//
+	{
+	char message[MaxOutputMsg+1];
+	TInt len = aDes.Length();
+	const char* ptr = (const char*)aDes.Ptr();
+	if (iLogTimeStamp)
+		{
+		strcpy(message,"          ");
+		_ultoa(NKern::TickCount() * iTimer.Period(), message + 10, 10);
+		int n = strlen(message);
+		len = min(len, MaxOutputMsg - n - 2);
+		char* msg = message + n;
+		msg[0] = msg[-1];
+		msg[-1] = n < 10+2 ? '0' : msg[-2];
+		msg[-2] = n < 10+3 ? '0' : msg[-3];
+		msg[-3] = '.';
+		if (n < 10+4)
+			msg[-4] = '0';
+		++msg;
+		*msg++ = '\t';
+		strncpy(msg, ptr, len);
+		msg[len] = 0;
+		ptr = msg - 11;
+		len += 11;
+		}
+	else
+		{
+		len = min(len, MaxOutputMsg);
+		strncpy(message, ptr, len);
+		message[len] = 0;
+		ptr = message;
+		}
+	TInt irq = NKern::DisableAllInterrupts();
+	if (iLogToFile)
+		{
+		DWORD bytes;
+		WriteFile(DebugOutput(), ptr, len, &bytes, NULL);
+		}
+	if (iLogToDebugger)
+		{
+		OutputDebugStringA(message);
+		}
+
+	NKern::RestoreInterrupts(irq);
+	}
+
+const char* const KErrorTitles[] =
+	{
+	"Symbian OS Fatal Error",
+	"Symbian OS Application Error"
+	};
+
+const TText8* const KErrorMsg[] =
+	{
+	_S8("An error has been detected in the Symbian OS emulator."),
+	_S8("A call to User::Panic() has occured, indicating\n"
+		"a programming fault in the running application.\n"
+		"Please refer to the documentation for more details.")
+	};
+
+_LIT8(KProgram, "\n\nProgram\t");
+_LIT8(KError, "\nError\t");
+_LIT8(KIDFC, "an IDFC");
+_LIT8(KEscaped, "an escaped thread");
+_LIT8(KInterrupt, "an interrupt thread");
+_LIT8(KNThread, "an NThread");
+_LIT8(KColon, " : ");
+_LIT8(KDebugQuery, "\n\nDo you wish to Debug the error?\0");
+
+TBool Wins::ErrorDialog(TError aType, const TDesC8& aPanic, TInt aVal)
+	{
+	// Must be called with interrupts enabled to allow thread running windows message loop to run
+	
+	TBuf8<512> message(KErrorMsg[aType]);
+	message.Append(KProgram);
+	TInt context = NKern::CurrentContext();
+	switch(context)
+		{
+		case NKern::EIDFC:
+			message.Append(KIDFC);
+			break;
+		case NKern::EEscaped:
+			message.Append(KEscaped);
+			break;
+		case NKern::EInterrupt:
+			message.Append(KInterrupt);
+			break;
+		case NKern::EThread:
+			DThread *thread = Kern::NThreadToDThread(NKern::CurrentThread());
+			if (thread)
+				thread->TraceAppendFullName(message, ETrue);
+			else
+				message.Append(KNThread);
+			break;
+		}
+	message.Append(KError);
+	message.Append(aPanic);
+	message.Append(KColon);
+	message.AppendNum(aVal);
+#ifdef _DEBUG
+	message.Append(KDebugQuery);
+	UINT type = MB_YESNO | MB_DEFBUTTON2;
+#else
+	UINT type = MB_OK;
+#endif
+	type |= MB_SETFOREGROUND  | MB_ICONERROR;
+	message.Append('\0');
+
+	TInt r = MessageBoxA(iUi ? iUi->HWnd() : NULL, (LPCSTR)message.Ptr(), KErrorTitles[aType], type);
+	return r == IDYES;
+	}
+
+// UI installation
+
+EXPORT_C DWinsUiBase::DWinsUiBase()
+	{
+	TheVariant.InstallUi(*this);
+	}
+
+
+TInt BinaryPowerInit();
+
+DWinsPowerController* DWinsPowerController::New()
+	{
+	DWinsPowerController* self = new DWinsPowerController();
+	if (!self)
+		return NULL;
+	self->iStandbySem = CreateSemaphore(NULL, 0, 1, NULL);
+	if (self->iStandbySem == NULL)
+		return NULL;
+	TInt r = BinaryPowerInit();
+	if (r != KErrNone)
+		return NULL;
+	self->Register();
+	return self; 
+	}
+
+void DWinsPowerController::CpuIdle()
+	{
+	Arch::TheAsic()->Idle();
+	}
+		
+void DWinsPowerController::EnableWakeupEvents()
+	{
+	iWakeupSignal = EFalse;
+	}
+
+void DWinsPowerController::DisableWakeupEvents()
+	{
+	}
+
+void DWinsPowerController::AbsoluteTimerExpired()
+	{
+	if (iTargetState == EPwStandby)
+		DWinsPowerController::WakeupEvent();	
+	}
+
+void DWinsPowerController::WakeupEvent()
+	{
+	if (iTargetState == EPwStandby)
+		{
+		iWakeupSignal = ETrue;
+		DPowerController::WakeupEvent();
+		}
+	}
+
+// called in Epoc thread
+void DWinsPowerController::PowerDown(TTimeK aWakeupTime)
+	{
+	if (iTargetState == EPwStandby)
+		{
+		UINT timeoutMs;
+		if (aWakeupTime == 0)
+			timeoutMs = INFINITE;
+		else 
+			{
+			TTimeK now = Kern::SystemTime();
+			if (now > aWakeupTime)
+				timeoutMs = 0;
+			else
+				timeoutMs = (UINT)((aWakeupTime - now) / 1000);
+			}
+		TInt l = NKern::DisableAllInterrupts();
+		if (!iWakeupSignal && timeoutMs)
+			{
+			iStandby = ETrue;
+			TheVariant.iTimer.Standby();
+			NKern::RestoreInterrupts(l);
+			DWORD r = WaitForSingleObject(iStandbySem, timeoutMs);
+			if (r == WAIT_TIMEOUT)
+				{
+				l = NKern::DisableAllInterrupts();
+				if (!iStandby)
+					WaitForSingleObject(iStandbySem, INFINITE);
+				else
+					iStandby = EFalse;
+				NKern::RestoreInterrupts(l);
+				}
+			TheVariant.iTimer.Wakeup();
+			}
+		else
+			NKern::RestoreInterrupts(l);
+
+		}
+	else
+		Kern::Restart(0x80000000);
+	}
+
+// called in the interrupt context
+void DWinsPowerController::AssertWakeupSignal()
+	{
+	iWakeupSignal = ETrue;
+	if (iStandby)
+		{
+		iStandby = EFalse;
+		ReleaseSemaphore(iStandbySem, 1, NULL);
+		}
+	}
+
+
+EXPORT_C void Wins::AssertWakeupSignal()
+	{
+	iPowerController->AssertWakeupSignal();
+	}
+
+EXPORT_C void Wins::WakeupEvent()
+	{
+	iPowerController->DWinsPowerController::WakeupEvent();
+	}
+
+// MMC emulation support
+
+TBool Wins::MediaDoorOpen;
+TInt Wins::CurrentPBusDevice;
+TAny* Wins::MediaChangeCallbackParam;
+TMediaChangeCallBack Wins::MediaChangeCallBackPtr;
+
+
+EXPORT_C TBool* Wins::MediaDoorOpenPtr()
+//
+// For media change simulation
+//
+	{
+
+	return(&MediaDoorOpen);
+	}
+
+EXPORT_C TInt* Wins::CurrentPBusDevicePtr()
+//
+// For media change simulation
+//
+	{
+
+	return(&CurrentPBusDevice);
+	}
+
+EXPORT_C void Wins::SetMediaChangeCallBackPtr(TMediaChangeCallBack aPtr, TAny* aMediaChangeCallbackParam)
+//
+// For media change simulation
+//
+	{
+	MediaChangeCallbackParam=aMediaChangeCallbackParam;
+	MediaChangeCallBackPtr=aPtr;
+	}
+
+EXPORT_C void Wins::MediaChangeCallBack()
+//
+// Perform the simulated media change callback
+//
+	{
+	if(MediaChangeCallBackPtr)
+		(*MediaChangeCallBackPtr)(MediaChangeCallbackParam);
+	}