kerneltest/e32test/system/d_mstim.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/system/d_mstim.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,977 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// e32test\system\d_mstim.cpp
+// LDD for testing millisecond timer
+// 
+//
+
+#include "plat_priv.h"
+#if defined(__MEIG__)
+#include <cl7211.h>
+#elif defined(__MAWD__)
+#include <windermere.h>
+#elif defined(__MISA__)
+#include <sa1100.h>
+#elif defined(__MCOT__)
+#include <cotulla.h>
+#elif defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) 
+#include <omap.h>
+#include <omap_timer.h>
+#elif defined(__MI920__) || defined(__NI1136__)
+#ifdef __MI920__
+#define USE_CM920_FRC
+#endif
+#ifdef USE_CM920_FRC
+#include <iolines.h>
+#else
+#include <integratorap.h>
+#endif
+#elif defined(__RVEMUBOARD__)
+#include <rvemuboard.h>
+#elif defined(__NE1_TB__)
+#include <upd35001_timer.h>
+#endif
+#include "d_mstim.h"
+#include "../misc/prbs.h"
+
+#if defined(__WINS__)
+typedef Int64 TCounter;
+typedef Int64 TDelta;
+const TDelta KMaxDelta = 0x7fffffffffffffff;
+const TDelta KMinDelta = 0x8000000000000000;
+#else
+typedef TUint TCounter;
+typedef TInt TDelta;
+const TDelta KMaxDelta = KMaxTInt;
+const TDelta KMinDelta = KMinTInt;
+#endif
+
+#ifdef __MISA__
+inline TCounter TIMER()
+	{ return *(volatile TUint*)KHwRwOstOscr; }
+#endif
+#if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) 
+inline TCounter TIMER()
+	{ return TOmapTimer::Timer3Value(); }
+#endif
+#ifdef __MCOT__
+inline TCounter TIMER()
+	{ return *(volatile TUint*)KHwRwOstOscr; }
+#endif
+#ifdef __MAWD__
+inline TCounter TIMER()
+	{ return *(volatile TUint*)(KWindBaseAddress+KWindTimer1Value16)&0xffff; }
+#endif
+#ifdef __MEIG__
+inline TCounter TIMER()
+{ return *(volatile TUint*)(KEigerBaseAddress+KEigerTimer1Data16)&0xffff;}
+#endif
+#if defined(__MI920__) || defined(__NI1136__)
+inline TCounter TIMER()
+#ifdef USE_CM920_FRC
+	{ return *(volatile TUint*)(KHwRwCoreClkCounter);}		// 32-bit Core module counter inc's at 24MHz
+#else
+	{ return *(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff;}
+#endif
+#endif
+#if defined(__RVEMUBOARD__)
+inline TCounter TIMER()
+	{ return *(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff;}
+#endif
+#ifdef __NE1_TB__
+inline TCounter TIMER()
+	{ return NETimer::Timer(2).iTimerCount; }
+#endif
+#if defined(__EPOC32__) && defined(__CPU_X86)
+TCounter TIMER();
+void SetUpTimerChannel2();
+#endif
+
+#ifdef __WINS__
+inline TCounter TIMER()
+	{
+	LARGE_INTEGER c;
+	QueryPerformanceCounter(&c);
+	return c.QuadPart;
+	}
+#endif
+
+#if defined(__MISA__) || (defined(USE_CM920_FRC) && (defined(__MI920__) || defined(__NI1136__)))
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return final-initial; }				// SA1100 timer counts up
+#endif
+#if defined(__MCOT__)
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return final-initial; }				// Cotulla timer counts up
+#endif
+#if defined(__MAWD__) || defined(__MEIG__) || (!defined(USE_CM920_FRC) && (defined(__MI920__) || defined(__NI1136__))) 
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return (initial-final)&0xffff; }		// Eiger/Windermere/Integrator timer counts down
+#endif
+#if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return (initial-final);}		// OMAP timer counts down
+#endif
+#if defined(__EPOC32__) && defined(__CPU_X86)
+TDelta TimeDelta(TUint initial, TUint final)
+	{
+	TUint tickdiff=(initial-final)&0xffff;
+	TUint msdiff=((final>>16)-(initial>>16))&0xffff;
+	msdiff=1193*msdiff-tickdiff;
+	msdiff=(msdiff+32768)&~0xffff;
+	return msdiff+tickdiff;
+	}
+#endif
+#ifdef __NE1_TB__
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return final - initial; }
+#endif
+#ifdef __WINS__
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return final-initial; }		// counts up
+#endif
+#if defined(__RVEMUBOARD__)
+inline TDelta TimeDelta(TCounter initial, TCounter final)
+	{ return (initial-final)&0xffff; }		// Timer counts down
+#endif
+
+const TInt KMajorVersionNumber=0;
+const TInt KMinorVersionNumber=1;
+const TInt KBuildVersionNumber=1;
+
+const TInt KMaxMsTim=9;
+const TInt KMaxMsTimR=9;
+
+TInt TicksToMicroseconds(TDelta aTicks)
+	{
+#if defined(__MISA__) || defined(__MCOT__)
+	Int64 ticks(aTicks);
+	ticks*=(1000000);
+	ticks+=KHwOscFreqHz/2;		// 3.6864MHz tick
+	ticks/=KHwOscFreqHz;
+	return (TInt)ticks;
+#endif
+#if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) 
+	// Timer runs at 12Mhz/32 = 375kHz. Each tick is 2.66...us which is 16/6us
+	aTicks<<=4;		// * 16
+	aTicks+=3;	    // rounding to the closest number of us
+	return (TInt)(aTicks/6);	// us = (ticks*16+3)/6
+#endif
+#if defined(__MI920__) || defined(__NI1136__)
+#if defined(USE_CM920_FRC)
+	Int64 ticks(aTicks);
+	ticks*=(1000000);
+	ticks+=24000000/2;
+	ticks/=24000000;
+	return (TInt)ticks;
+#else
+	aTicks<<=14;	// 1 tick = 32/3 us
+	aTicks+=768;	// round
+	return (TInt)(aTicks/1536);
+#endif
+#endif
+#if defined(__RVEMUBOARD__)
+	return (TInt)(aTicks*256);  // 1 tick = 256 us
+#endif
+#if defined(__MAWD__) || defined(__MEIG__)
+	return aTicks*500;					// 2kHz tick
+#endif
+#if defined(__NE1_TB__)
+	NETimer& T2 = NETimer::Timer(2);
+	TUint prescale = __e32_find_ms1_32(T2.iPrescaler & 0x3f);
+	TInt f = 66666667 >> prescale;
+	TInt64 x = I64LIT(1000000);
+	x *= TInt64(aTicks);
+	x += TInt64(f>>1);
+	x /= TInt64(f);
+	return (TInt)x;
+#endif
+#if defined(__EPOC32__) && defined(__CPU_X86)
+	TInt x = aTicks;
+	TInt y = x;
+	y -= ((3*x)>>4);	// * 0.D
+	y += (aTicks>>12);	// * 0.D00D
+	TInt z = (6*x)>>8;	// * 0.06
+	y += z;				// * 0.D60D
+	y += (x>>9);		// * 0.D68D
+	y += (z>>16);		// * 0.D68D6
+	y += (z>>20);		// * 0.D68D66
+	return y;
+#endif
+#ifdef __WINS__
+	LARGE_INTEGER f;
+	QueryPerformanceFrequency(&f);
+	aTicks*=1000000;
+	aTicks+=f.QuadPart-1;
+	aTicks/=f.QuadPart;
+	return (TInt)aTicks;
+#endif
+	}
+
+
+void InitTimer()
+	{
+#ifdef __MAWD__
+	// Set up timer 1 as free running 2kHz clock
+	TWind::SetBuzzerControl(0);		// disable buzzer
+	TWind::SetTimer1Control(KWindTimer1ControlTimerEnable);
+	TWind::SetTimer1Load(0);
+#endif
+#ifdef __MEIG__
+	// Set up timer 1 as free running 2kHz clock
+	TEiger::ModifyControl21(KEigerControlTimer1PreOrFree|KEigerControlTimer1K512OrK2|
+							KEigerControlBuzzerToggle|KEigerControlBuzzerTimer1OrToggle,0);
+	TEiger::SetTimer1Data(0);
+#endif
+#if defined(__MISA__)
+	// MISA free running counter is always active - no initialisation required
+#endif
+#if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
+	// Set up Timer3 as a free-running timer at 12Mhz/32 = 375kHz
+	TOmapTimer::SetTimer3Ctrl(	TOmapTimer::KHtOSTimer_Cntl_Ar
+									| TOmapTimer::KHtOSTimer_Cntl_Free
+									| TOmapTimer::KHtOSTimer_Cntl_ClkEnable );
+	TOmapTimer::SetTimer3Prescale( TOmapTimer::EPrescaleBy32 );
+	// Autoreload 0xFFFFFFFF to effectively wrap from zero back to 0xFFFFFFFF
+	TOmapTimer::SetTimer3LoadTim( 0xFFFFFFFF );
+	TOmapTimer::StartTimer3();
+#endif
+#if defined(__MI920__) || defined(__NI1136__)
+#if !defined(USE_CM920_FRC)
+    TIntegratorAP::SetTimerMode(TIntegratorAP::ECounterTimer1, TIntegratorAP::ETimerModeFreeRunning);
+    TIntegratorAP::SetTimerPreScale(TIntegratorAP::ECounterTimer1, TIntegratorAP::ETimerPreScaleDiv256);	// 93.75kHz wrap 699ms
+    TIntegratorAP::EnableTimer(TIntegratorAP::ECounterTimer1, TIntegratorAP::EEnable);
+#endif
+#endif
+#if defined(__RVEMUBOARD__)
+	// Switch timer 1 to a 1MHz clock in the system controller Ctrl register
+	TRvEmuBoard::SetSCCtrl(KTimer1EnSel);
+
+	// Set up timer 1 as free running 3.90625kHz clock
+	TRvEmuBoard::SetTimerMode(KHwCounterTimer1, TRvEmuBoard::ETimerModeFreeRunning);
+	TRvEmuBoard::SetTimerPreScale(KHwCounterTimer1, TRvEmuBoard::ETimerPreScaleDiv256);// 3.90625kHz wrap 16.777s
+	TRvEmuBoard::EnableTimer(KHwCounterTimer1, TRvEmuBoard::EEnable);
+#endif
+#if defined(__NE1_TB__)
+	// nothing to do since variant has already set up timer
+#endif
+#if defined(__EPOC32__) && defined(__CPU_X86)
+	// Set up timer channel 2 as free running counter at 14318180/12 Hz
+	SetUpTimerChannel2();
+#endif
+	}
+
+// global Dfc Que
+TDynamicDfcQue* gDfcQ;
+
+class NTimerQTest
+	{
+public:
+	static inline NTimerQ& Timer()
+		{ return *(NTimerQ*)NTimerQ::TimerAddress(); }
+	static inline TUint32 MsCount()
+		{ return Timer().iMsCount; }
+	static inline void Setup(TAny* aPtr)
+		{ NTimerQ& m=Timer(); m.iDebugFn=Test; m.iDebugPtr=aPtr; }
+	static inline void Stop()
+		{ NTimerQ& m=Timer(); m.iDebugFn=NULL; m.iDebugPtr=NULL; }
+	static inline TBool XferC()
+		{ return Timer().iTransferringCancelled; }
+	static inline TBool CritC()
+		{ return Timer().iCriticalCancelled; }
+	static void Test(TAny* aPtr, TInt aPos);
+	};
+
+class DMsTim;
+
+class TMsTim : public NTimer
+	{
+public:
+	enum TMode
+		{
+		EIntAfter,
+		EDfcAfter,
+		EIntAgain,
+		EDfcAgain,
+		EIntCancel,
+		EDfcCancel,
+		EUserDfcAfter
+		};
+
+	enum TModeX
+		{
+		EIntAgainOnce=7,
+		EUserDfcAgainOnce
+		};
+public:
+	TMsTim();
+	~TMsTim();
+	TInt Create();
+	TInt Start(TInt aMode, TInt aInterval, TInt aParam);
+	static void MsCallBack(TAny* aPtr);
+	static void IDfcFn(TAny* aPtr);
+	static void DfcFn(TAny* aPtr);
+	void CompleteClient(TInt aValue);
+public:
+	TMode iMode;
+	TInt iInterval;
+	TInt iParam;
+	TCounter iStartTime;
+	TDelta iMin;
+	TDelta iMax;
+	Int64 iTotal;
+	TInt iCount;
+	DMsTim* iLdd;
+	TInt iId;
+	TClientRequest* iRequest;
+	TDfc iIDfc;
+	TDfc iCompletionDfc;
+	};
+
+class TMsTimRand : public NTimer
+	{
+public:
+	TMsTimRand();
+#ifdef __SMP__
+	~TMsTimRand();
+#endif
+	TInt Start(TInt aInterval, DMsTim* aLdd, TInt aPos);
+	static void MsCallBack(TAny* aPtr);
+	void FillWithGarbage(TUint aFillValue);
+public:
+	TInt iInterval;
+	TCounter iStartTime;
+	DMsTim* iLdd;
+	};
+
+class DMsTimFactory : public DLogicalDevice
+//
+// Millisecond timer LDD factory
+//
+	{
+public:
+	DMsTimFactory();
+	~DMsTimFactory();
+	virtual TInt Install();						//overriding pure virtual
+	virtual void GetCaps(TDes8& aDes) const;	//overriding pure virtual
+	virtual TInt Create(DLogicalChannelBase*& aChannel);	//overriding pure virtual
+	};
+
+class DMsTim : public DLogicalChannel
+//
+// Millisecond timer LDD channel
+//
+	{
+public:
+	DMsTim();
+	~DMsTim();
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	TInt DoControl(TInt aFunction, TAny* a1, TAny* a2);
+	TInt DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2);
+	virtual void HandleMsg(TMessageBase* aMsg);
+public:
+	void TimerExpired(TInt anId);
+	inline DThread* Client() { return iThread; }
+public:
+	DThread* iThread;
+	TMsTim iMsTim[KMaxMsTim];
+	TMsTimRand iMsTimR[KMaxMsTimR];
+	TInt iRandMin;
+	TInt iRandMax;
+	TInt iXferC;
+	TInt iCritC;
+	TInt iStartFail;
+	TInt iCallBacks;
+	TInt iCompletions;
+	TUint iSeed[2];
+	};
+
+TMsTim::TMsTim()
+	:	NTimer(MsCallBack,this),
+		iMode(EIntAfter),
+		iInterval(0),
+		iParam(0),
+		iStartTime(0),
+		iMin(KMaxDelta),
+		iMax(KMinDelta),
+		iTotal(0),
+		iCount(0),
+		iRequest(NULL),
+		iIDfc(IDfcFn,this),
+		iCompletionDfc(DfcFn,this,gDfcQ,1)
+	{
+	}
+
+TMsTim::~TMsTim()
+	{
+	Kern::DestroyClientRequest(iRequest);
+#ifdef __SMP__
+	NTimer* nt = STATIC_CAST(NTimer*,this);
+	new (nt) NTimer(&MsCallBack, this);	// so NTimer destructor doesn't kill us
+#endif
+	}
+
+TInt TMsTim::Create()
+	{
+	return Kern::CreateClientRequest(iRequest);
+	}
+
+void TMsTim::IDfcFn(TAny* aPtr)
+	{
+	TMsTim& m=*(TMsTim*)aPtr;
+	TInt c = NKern::CurrentContext();
+	__NK_ASSERT_ALWAYS(c == NKern::EIDFC);
+	__NK_ASSERT_ALWAYS(NKern::KernelLocked(1));
+	m.iCompletionDfc.DoEnque();
+	}
+
+void TMsTim::DfcFn(TAny* aPtr)
+	{
+	TMsTim& m=*(TMsTim*)aPtr;
+	if (m.iMode==EUserDfcAfter)
+		{
+		TCounter timer_val=TIMER();
+		TDelta time=TimeDelta(m.iStartTime, timer_val);
+		++m.iCount;
+		if (time<m.iMin)
+			m.iMin=time;
+		if (time>m.iMax)
+			m.iMax=time;
+		m.iTotal+=time;
+		}
+	m.iLdd->TimerExpired(m.iId);
+	}
+
+void TestThreadContext()
+	{
+	TInt c1 = NKern::CurrentContext();
+	NKern::Lock();
+	TInt c2 = NKern::CurrentContext();
+	NKern::Unlock();
+	__NK_ASSERT_ALWAYS((c1 == NKern::EThread) && (c2 == NKern::EThread));
+	}
+
+void TMsTim::MsCallBack(TAny* aPtr)
+	{
+	TInt c = NKern::CurrentContext();
+	TCounter timer_val=TIMER();
+	TMsTim& m=*(TMsTim*)aPtr;
+	TDelta time=TimeDelta(m.iStartTime, timer_val);
+	if (++m.iCount>0 || (m.iMode!=EIntAgain && m.iMode!=EDfcAgain))
+		{
+		if (time<m.iMin)
+			m.iMin=time;
+		if (time>m.iMax)
+			m.iMax=time;
+		m.iTotal+=time;
+		}
+	switch (m.iMode)
+		{
+		case EIntAfter:
+			__NK_ASSERT_ALWAYS(c == NKern::EInterrupt);
+			m.iIDfc.Add();
+			break;
+		case EDfcAfter:
+			TestThreadContext();
+			m.iCompletionDfc.Enque();
+			break;
+		case EIntAgain:
+			__NK_ASSERT_ALWAYS(c == NKern::EInterrupt);
+			m.iStartTime=TIMER();
+			m.Again(m.iInterval);
+			break;
+		case EDfcAgain:
+			TestThreadContext();
+			m.iStartTime=TIMER();
+			m.Again(m.iInterval);
+			break;
+		case EIntCancel:
+			__NK_ASSERT_ALWAYS(c == NKern::EInterrupt);
+			m.iLdd->iMsTim[m.iParam].Cancel();
+			m.iIDfc.Add();
+			break;
+		case EDfcCancel:
+			TestThreadContext();
+			m.iLdd->iMsTim[m.iParam].Cancel();
+			m.iCompletionDfc.Enque();
+			break;
+		case EUserDfcAfter:
+			__NK_ASSERT_ALWAYS(EFalse);
+			break;
+		}
+	}
+
+TInt TMsTim::Start(TInt aMode, TInt aInterval, TInt aParam)
+	{
+	TInt r=KErrGeneral;
+	TInt c=0;
+	TCounter holder=TIMER();		// holds the start value of timer
+	switch (aMode)
+		{
+		case EIntAgain:
+			c=-1;
+		case EIntAfter:
+		case EIntCancel:
+			r=OneShot(aInterval);
+			break;
+		case EDfcAgain:
+			c=-1;
+		case EDfcAfter:
+		case EDfcCancel:
+			r=OneShot(aInterval,ETrue);
+			break;
+		case EIntAgainOnce:
+		case EUserDfcAgainOnce:
+#ifdef __SMP__
+			i8888.iHState2=FALSE;
+#else
+			iCompleteInDfc=FALSE;
+#endif
+			r=Again(aInterval);
+			if (aMode==EUserDfcAgainOnce)
+				aMode=EUserDfcAfter;
+			else
+				aMode=EIntAfter;
+			break;
+		case EUserDfcAfter:
+			r=OneShot(aInterval, iCompletionDfc);
+			break;
+		}
+	if (r!=KErrNone)
+		return r;
+	iStartTime=holder;
+	iMode=TMode(aMode);
+	iInterval=aInterval;
+	iParam=aParam;
+	iMin=KMaxDelta;
+	iMax=KMinDelta;
+	iTotal=0;
+	iCount=c;
+	return KErrNone;
+	}
+
+void TMsTim::CompleteClient(TInt aValue)
+	{
+	Kern::QueueRequestComplete(iLdd->Client(),iRequest,aValue);
+	}
+
+TMsTimRand::TMsTimRand()
+	:	NTimer(&MsCallBack,this)
+	{
+	memset(this,0,sizeof(TMsTimRand));
+#ifdef __SMP__
+	NTimer* nt = STATIC_CAST(NTimer*,this);
+	new (nt) NTimer(&MsCallBack,this);
+#else
+	iFunction=MsCallBack;	// avoid triggering assertion in NTimer::OneShot()
+#endif
+	}
+
+#ifdef __SMP__
+TMsTimRand::~TMsTimRand()
+	{
+	NTimer* nt = STATIC_CAST(NTimer*,this);
+	new (nt) NTimer(&MsCallBack, this);	// so NTimer destructor doesn't kill us
+	}
+#endif
+
+void TMsTimRand::FillWithGarbage(TUint aFill)
+	{
+#ifdef __SMP__
+	TUint32 f = aFill;
+	f |= (f<<8);
+	f |= (f<<16);
+	iNext = (SDblQueLink*)f;
+	iPrev = (SDblQueLink*)f;
+	iDfcQ = (TDfcQue*)f;
+	iPtr = (TAny*)f;
+	iFn = (NEventFn)f;
+	iTiedLink.iNext = (SDblQueLink*)f;
+	iTiedLink.iPrev = (SDblQueLink*)f;
+#else
+	memset(this, (TUint8)aFill, 16);
+#endif
+	}
+
+TInt TMsTimRand::Start(TInt aInterval, DMsTim* aLdd, TInt aPos)
+	{
+	iLdd=aLdd;
+#ifdef __SMP__
+	TUint fill=(aPos<<5)|(i8888.iHState1<<2)|3;
+#else
+	TUint fill=(aPos<<5)|(iState<<2)|3;
+	iPad1 = (TUint8)fill;
+#endif
+	TInt r=OneShot(aInterval,ETrue);
+	if (r==KErrNone)
+		{
+		iPtr=this;
+		iInterval=aInterval;
+		iStartTime=TIMER();
+#ifdef __SMP__
+		iFn=MsCallBack;
+		i8888.iHState0 = (TUint8)fill;
+		if (i8888.iHState1!=EHolding)
+			*(TUint*)0xfcd1fcd1=i8888.iHState1;
+#else
+		iFunction=MsCallBack;
+		iUserFlags = (TUint8)fill;
+		if (iState!=EHolding)
+			*(TUint*)0xfcd1fcd1=iState;
+#endif
+		}
+	return r;
+	}
+
+void TMsTimRand::MsCallBack(TAny* aPtr)
+	{
+	TMsTimRand& m=*(TMsTimRand*)aPtr;
+	TCounter time=TIMER();
+	TDelta elapsed=TimeDelta(m.iStartTime,time);
+	TInt error=TicksToMicroseconds(elapsed)-m.iInterval*1000;
+	if (error<m.iLdd->iRandMin)
+		m.iLdd->iRandMin=error;
+	if (error>m.iLdd->iRandMax)
+		m.iLdd->iRandMax=error;
+	++m.iLdd->iCompletions;
+	m.FillWithGarbage(0xd9);
+	}
+
+void NTimerQTest::Test(TAny* aPtr, TInt aPos)
+	{
+	DMsTim& ldd=*(DMsTim*)aPtr;
+	++ldd.iCallBacks;
+	if (aPos==7)
+		return;
+	TUint action=Random(ldd.iSeed)&31;
+	TMsTimRand& m=ldd.iMsTimR[action&7];
+	if (action<8)
+		{
+#ifdef __SMP__
+		TUint fill=(aPos<<5)|(m.i8888.iHState1<<2)|3;
+#else
+		TUint fill=(aPos<<5)|(m.iState<<2)|3;
+#endif
+		m.Cancel();
+		m.FillWithGarbage(fill);
+		}
+	else if (action<16)
+		{
+		TUint iv=(Random(ldd.iSeed)&31)+32;
+		TInt r=m.Start(iv,&ldd,aPos);
+		if (r!=KErrNone)
+			++ldd.iStartFail;
+		}
+	if (XferC())
+		++ldd.iXferC;
+	if (CritC())
+		++ldd.iCritC;
+	}
+
+DECLARE_STANDARD_LDD()
+	{
+    return new DMsTimFactory;
+    }
+
+DMsTimFactory::DMsTimFactory()
+//
+// Constructor
+//
+    {
+    iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    //iParseMask=0;//No units, no info, no PDD
+    //iUnitsMask=0;//Only one thing
+    }
+
+TInt DMsTimFactory::Create(DLogicalChannelBase*& aChannel)
+//
+// Create a new DMsTim on this logical device
+//
+    {
+	aChannel=new DMsTim;
+	return aChannel?KErrNone:KErrNoMemory;
+    }
+
+const TInt KDMsTimThreadPriority = 27;
+_LIT(KDMsTimThread,"DMsTimThread");
+
+TInt DMsTimFactory::Install()
+//
+// Install the LDD - overriding pure virtual
+//
+    {
+	// Allocate a kernel thread to run the DFC 
+	TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDMsTimThreadPriority, KDMsTimThread);
+
+	if (r != KErrNone)
+		return r; 	
+
+    return SetName(&KMsTimerLddName);
+    }
+
+void DMsTimFactory::GetCaps(TDes8& aDes) const
+//
+// Get capabilities - overriding pure virtual
+//
+    {
+    TCapsMsTimV01 b;
+    b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
+    }
+
+/**
+  Destructor
+*/
+DMsTimFactory::~DMsTimFactory()
+	{
+	if (gDfcQ)
+		gDfcQ->Destroy();
+	}
+
+DMsTim::DMsTim()
+//
+// Constructor
+//
+    {
+	iThread=&Kern::CurrentThread();
+	iThread->Open();
+	TInt i;
+	for (i=0; i<KMaxMsTim; i++)
+		{
+		iMsTim[i].iLdd=this;
+		iMsTim[i].iId=i;
+		}
+	for (i=0; i<KMaxMsTimR; i++)
+		{
+		iMsTimR[i].iLdd=this;
+		}
+	iSeed[0]=NTimerQTest::MsCount();
+	iSeed[1]=0;
+    }
+
+TInt DMsTim::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
+//
+// Create channel
+//
+    {
+    if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
+    	return KErrNotSupported;
+	InitTimer();
+	SetDfcQ(gDfcQ);
+	for (TInt i = 0 ; i < KMaxMsTim ; ++i)
+		{
+		TInt r = iMsTim[i].Create();
+		if (r != KErrNone)
+			return r;
+		}
+	iMsgQ.Receive();
+#ifdef __SMP__
+	NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), NKern::NumberOfCpus() - 1); // Try and avoid the cpu the test app is running on
+#endif
+	return KErrNone;
+	}
+
+DMsTim::~DMsTim()
+//
+// Destructor
+//
+    {
+#if defined(__MI920__) || defined(__NI1136__)
+#if !defined(USE_CM920_FRC)
+	TIntegratorAP::EnableTimer(TIntegratorAP::ECounterTimer1, TIntegratorAP::EDisable);
+#endif
+#endif
+#if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) 
+	TOmapTimer::SetTimer3Ctrl( 0 );	// disable the timer
+#endif
+	Kern::SafeClose((DObject*&)iThread, NULL);
+    }
+
+void DMsTim::HandleMsg(TMessageBase* aMsg)
+	{
+	TInt r=KErrNone;
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+	TInt id=m.iValue;
+	if (id==(TInt)ECloseMsg)
+		{
+		NTimerQTest::Stop();
+		TInt i;
+		for (i=0; i<KMaxMsTim; i++)
+			{
+			iMsTim[i].Cancel();
+			iMsTim[i].iCompletionDfc.Cancel();
+			iMsTim[i].CompleteClient(KErrCancel);
+			}
+		for (i=0; i<KMaxMsTimR; i++)
+			{
+			iMsTimR[i].Cancel();
+			iMsTimR[i].FillWithGarbage(0x01);
+			}
+		m.Complete(KErrNone,EFalse);
+		iMsgQ.CompleteAll(KErrServerTerminated);
+		return;
+		}
+	else if (id<0)
+		{
+		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+		r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
+		}
+	else
+		{
+		r=DoControl(id,m.Ptr0(),m.Ptr1());
+		}
+	m.Complete(r,ETrue);
+	}
+
+TInt DMsTim::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	TInt r=KErrNone;
+	TInt id=(TInt)a1;
+	TMsTim& m=iMsTim[id];
+	TInt interval=(TInt)a2;
+	switch (aFunction)
+		{
+		case RMsTim::EControlStartPeriodicInt:
+			r=m.Start(TMsTim::EIntAgain,interval,0);
+			break;
+		case RMsTim::EControlStartPeriodicDfc:
+			r=m.Start(TMsTim::EDfcAgain,interval,0);
+			break;
+		case RMsTim::EControlStopPeriodic:
+			m.Cancel();
+			m.iCompletionDfc.Cancel();
+			break;
+		case RMsTim::EControlGetInfo:
+			{
+			SMsTimerInfo info;
+			info.iMin=TicksToMicroseconds(m.iMin);
+			info.iMax=TicksToMicroseconds(m.iMax);
+			info.iCount=m.iCount;
+			Int64 avg=m.iTotal/m.iCount;
+			info.iAvg=TicksToMicroseconds((TInt)avg);
+
+			r=Kern::ThreadRawWrite(iThread,a2,&info,sizeof(info));
+			break;
+			}
+		case RMsTim::EControlBeginRandomTest:
+			{
+			iRandMin=KMaxTInt;
+			iRandMax=KMinTInt;
+			iXferC=0;
+			iCritC=0;
+			iStartFail=0;
+			iCallBacks=0;
+			iCompletions=0;
+			NTimerQTest::Setup(this);
+			break;
+			}
+		case RMsTim::EControlEndRandomTest:
+			{
+			NTimerQTest::Stop();
+			TInt i;
+			for (i=0; i<KMaxMsTimR; i++)
+				{
+				iMsTimR[i].Cancel();
+				iMsTimR[i].FillWithGarbage(0x35);
+				}
+			break;
+			}
+		case RMsTim::EControlGetRandomTestInfo:
+			{
+			SRandomTestInfo info;
+			info.iMin=iRandMin;
+			info.iMax=iRandMax;
+			info.iXferC=iXferC;
+			info.iCritC=iCritC;
+			info.iStartFail=iStartFail;
+			info.iCallBacks=iCallBacks;
+			info.iCompletions=iCompletions;
+			r=Kern::ThreadRawWrite(iThread,a1,&info,sizeof(info));
+			break;
+			}
+		case RMsTim::EControlGetIdleTime:
+			{
+			TInt irq=NKern::DisableAllInterrupts();
+			r=NTimerQ::IdleTime();
+			NKern::RestoreInterrupts(irq);
+			break;
+			}
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+
+TInt DMsTim::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+	{
+	TInt id=(TInt)a1;
+	TMsTim& m=iMsTim[aFunction == RMsTim::ERequestIntCancel ? 7 : id];
+	TInt interval=(TInt)a2;
+	TInt r=KErrNone;
+	switch (aFunction)
+		{
+		case RMsTim::ERequestOneShotInt:
+			r=m.Start(TMsTim::EIntAfter,interval,0);
+			break;
+		case RMsTim::ERequestOneShotDfc:
+			r=m.Start(TMsTim::EDfcAfter,interval,0);
+			break;
+		case RMsTim::ERequestIntCancel:
+			r=m.Start(TMsTim::EIntCancel,interval,id);
+			break;
+		case RMsTim::ERequestOneShotIntAgain:
+			r=m.Start(TMsTim::EIntAgainOnce,interval,0);
+			break;
+		case RMsTim::ERequestOneShotUserDfc:
+			r=m.Start(TMsTim::EUserDfcAfter,interval,0);
+			break;
+		case RMsTim::ERequestOneShotUserDfcAgain:
+			r=m.Start(TMsTim::EUserDfcAgainOnce,interval,0);
+			break;
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	m.iRequest->SetStatus(aStatus);
+	if (r!=KErrNone)
+		Kern::QueueRequestComplete(iThread,m.iRequest,r);
+	return r;
+	}
+
+void DMsTim::TimerExpired(TInt anId)
+	{
+	TMsTim& m=iMsTim[anId];
+	switch (m.iMode)
+		{
+		case TMsTim::EIntAfter:
+		case TMsTim::EDfcAfter:
+		case TMsTim::EUserDfcAfter:
+			m.CompleteClient(KErrNone);
+			break;
+		case TMsTim::EIntAgain:
+		case TMsTim::EDfcAgain:
+			break;
+		case TMsTim::EIntCancel:
+		case TMsTim::EDfcCancel:
+			{
+			TMsTim& cancelled=iMsTim[m.iParam];
+			cancelled.CompleteClient(KErrAbort);
+			m.CompleteClient(KErrNone);
+			break;
+			}
+		}
+	}
+