diff -r a179b74831c9 -r c1f20ce4abcf kerneltest/e32test/timestamp/d_timestamp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/timestamp/d_timestamp.cpp Tue Aug 31 16:34:26 2010 +0300 @@ -0,0 +1,461 @@ +// Copyright (c) 2010 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: +// d_timestamp.cpp +// + +#include +#include +#include "d_timestamp.h" +#include "d_timestamp_dev.h" + +// time stamp test defaults +static const TInt KTimerDurationS = 5; // time interval for NTimer +static const TInt KNErrPercent = 1; // percent error acceptable +static const TInt KIterations = 5; // required number of valid runs (with LPM entry) +static const TInt KRetries = 4; // retries are reset on every succesful run + +// +// DTimestampTestFactory +// + +/** + Standard export function for LDDs. This creates a DLogicalDevice derived object, + in this case, our DTimestampTestFactory +*/ +DECLARE_STANDARD_LDD() + { + return new DTimestampTestFactory; + } + +/** + Constructor +*/ +DTimestampTestFactory::DTimestampTestFactory() + { + // Set version number for this device + iVersion=RTimestampTest::VersionRequired(); + // Indicate that we work with a PDD + iParseMask=KDeviceAllowPhysicalDevice; + } + +/** + Second stage constructor for DTimestampTestFactory. + This must at least set a name for the driver object. + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTimestampTestFactory::Install() + { + return SetName(&RTimestampTest::Name()); + } + +/** + Destructor +*/ +DTimestampTestFactory::~DTimestampTestFactory() + { + + } + +/** + Return the drivers capabilities. + Called in the response to an RDevice::GetCaps() request. + + @param aDes User-side descriptor to write capabilities information into +*/ +void DTimestampTestFactory::GetCaps(TDes8& aDes) const + { + // Create a capabilities object + RTimestampTest::TCaps caps; + caps.iVersion = iVersion; + // Write it back to user memory + Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps)); + } + + +/** + Called by the kernel's device driver framework to create a Logical Channel. + This is called in the context of the user thread (client) which requested the creation of a Logical Channel + (E.g. through a call to RBusLogicalChannel::DoCreate) + The thread is in a critical section. + + @param aChannel Set to point to the created Logical Channel + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTimestampTestFactory::Create(DLogicalChannelBase*& aChannel) + { + aChannel=new DTimestampTestChannel; + if(!aChannel) + { + return KErrNoMemory; + } + + return KErrNone; + } + + +// +// Logical Channel +// + +/** + Constructor +*/ +DTimestampTestChannel::DTimestampTestChannel() + :iTimer(timerExpire,this),iDfc(dfcFn,this,7),iStarted(EFalse) + { + // Get pointer to client threads DThread object + iClient=&Kern::CurrentThread(); + // Open a reference on client thread so it's control block can't dissapear until + // this driver has finished with it. + // Note, this call to Open can't fail since its the thread we are currently running in + iClient->Open(); + } + +/** + Second stage constructor called by the kernel's device driver framework. + This is called in the context of the user thread (client) which requested the creation of a Logical Channel + (E.g. through a call to RBusLogicalChannel::DoCreate) + The thread is in a critical section. + + @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate + @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate + @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTimestampTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) + { + // Check version + if (!Kern::QueryVersionSupported(RTimestampTest::VersionRequired(),aVer)) + return KErrNotSupported; + + // Setup LDD for receiving client messages + TInt r = Kern::CreateClientRequest(iStartRequest); + if (r != KErrNone) return r; + r = Kern::CreateClientDataRequest(iWaitOnTimerRequest); + if (r != KErrNone) return r; + r = Kern::DynamicDfcQCreate(iQue,Kern::DfcQue0()->iThread->iPriority,RTimestampTest::Name()); + if (KErrNone!=r) return r; + iDfc.SetDfcQ(iQue); + SetDfcQ(iQue); + iMsgQ.Receive(); + // Done + return KErrNone; + } + + +/** + Destructor +*/ +DTimestampTestChannel::~DTimestampTestChannel() + { + // Cancel all processing that we may be doing + DoCancel(TUint(RTimestampTest::EAllRequests)); + Kern::DestroyClientRequest(iWaitOnTimerRequest); + Kern::DestroyClientRequest(iStartRequest); + iQue->Destroy(); + // Close our reference on the client thread + Kern::SafeClose((DObject*&)iClient,NULL); + } + +/** + Called when a user thread requests a handle to this channel. +*/ +TInt DTimestampTestChannel::RequestUserHandle(DThread* aThread, TOwnerType aType) + { + // Make sure that only our client can get a handle + if (aType!=EOwnerThread || aThread!=iClient) + return KErrAccessDenied; + return KErrNone; + } + +/** + override SendMsg method to allow pinning data in the context of the client thread +*/ +TInt DTimestampTestChannel::SendMsg(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + TInt id = m.iValue; + + // we only support one client + if (id != (TInt)ECloseMsg && m.Client() != iClient) + return KErrAccessDenied; + + TInt r = KErrNone; + if (id != (TInt)ECloseMsg && id != KMaxTInt) + { + if (id<0) + { + TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); + r = SendRequest(aMsg); + if (r != KErrNone) + Kern::RequestComplete(pS,r); + } + else + r = SendControl(aMsg); + } + else + r = DLogicalChannel::SendMsg(aMsg); + + return r; + } + +/** + Process a message for this logical channel. + This function is called in the context of a DFC thread. + + @param aMessage The message to process. + The iValue member of this distinguishes the message type: + iValue==ECloseMsg, channel close message + iValue==KMaxTInt, a 'DoCancel' message + iValue>=0, a 'DoControl' message with function number equal to iValue + iValue<0, a 'DoRequest' message with function number equal to ~iValue +*/ +void DTimestampTestChannel::HandleMsg(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + + // Get message type + TInt id=m.iValue; + + // Decode the message type and dispatch it to the relevent handler function... + + if (id==(TInt)ECloseMsg) + { + // Channel Close + DoCancel(TUint(RTimestampTest::EAllRequests)); + iMsgQ.CompleteAll(KErrServerTerminated); + m.Complete(KErrNone, EFalse); + return; + } + + if (id==KMaxTInt) + { + // DoCancel + DoCancel(m.Int0()); + m.Complete(KErrNone,ETrue); + return; + } + + if (id<0) + { + // DoRequest + TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); + DoRequest(~id,pS,m.Ptr1(),m.Ptr2()); + m.Complete(KErrNone,ETrue); + } + else + { + // DoControl + TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); + m.Complete(r,ETrue); + } + } + +/** + Preprocess synchronous 'control' requests +*/ +TInt DTimestampTestChannel::SendControl(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + TInt id=m.iValue; + + switch (id) + { + + case RTimestampTest::EConfig: + { + STimestampTestConfig info; +#ifdef __SMP__ + info.iFreq = NKern::TimestampFrequency(); +#else + info.iFreq = NKern::FastCounterFrequency(); +#endif + info.iIterations = KIterations; + info.iRetries = KRetries; + info.iTimerDurationS = KTimerDurationS; + info.iErrorPercent = KNErrPercent; + // Allow PDD to override defaults + Pdd().TestConfig(info); + kumemput(m.Ptr0(),&info,sizeof(STimestampTestConfig)); + return KErrNone; + } + + } + + + TInt r = DLogicalChannel::SendMsg(aMsg); + if (r != KErrNone) + return r; + +// switch (id) +// { +// } + + return r; + } + +/** + Process synchronous 'control' requests +*/ +TInt DTimestampTestChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) + { + (void)a2; + (void)a1; + (void) aFunction; + + // TInt r = KErrNone; + // switch (aFunction) + // { + // default: + // r = KErrNotSupported; + // } + + return KErrNotSupported; + } + + +/** + Preprocess asynchronous requests. +*/ +TInt DTimestampTestChannel::SendRequest(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + TInt function = ~m.iValue; + TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); + + TInt r = KErrNotSupported; + + switch (function) + { + case RTimestampTest::EStart: + if (!iStarted) + { + r = iStartRequest->SetStatus(pS); + } + else + { + r = KErrInUse; + } + break; + + case RTimestampTest::EWaitOnTimer: + if (iStarted) + { + iWaitOnTimerRequest->SetDestPtr(m.Ptr1()); + r = iWaitOnTimerRequest->SetStatus(pS); + } + else + { + r = KErrNotReady; + } + + break; + default: + r = KErrNotSupported; + } + + if (r == KErrNone) + r = DLogicalChannel::SendMsg(aMsg); + return r; + } + + +/** + Process asynchronous requests. +*/ +void DTimestampTestChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) + { + (void)a2; + (void)a1; + (void)aStatus; + + TInt r = KErrNone; + + switch(aReqNo) + { + case RTimestampTest::EStart: + iNTicks = (TInt) a1; + r = iTimer.OneShot(0); + if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iStartRequest,r); + break; + case RTimestampTest::EWaitOnTimer: + Pdd().StartLPMEntryCheck(); // PDD will start checking if we have entered LPM + r = iTimer.Again(iNTicks); + if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,r); + break; + } + + } + + + +/** + Process cancelling of asynchronous requests. +*/ +void DTimestampTestChannel::DoCancel(TUint aMask) + { + (void)aMask; + iTimer.Cancel(); // no real guarantees on SMP systems + iDfc.Cancel(); + } + + +/** + * process timer expiry +*/ +void DTimestampTestChannel::DoTimerExpire() + { +#ifdef __SMP__ + TUint64 ts = NKern::Timestamp(); +#else + TUint64 ts = NKern::FastCounter(); +#endif + iTimestampDelta = ts-iLastTimestamp; + iLastTimestamp = ts; + iDfc.Add(); + } + +void DTimestampTestChannel::timerExpire(TAny* aParam) + { + DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam; + pD->DoTimerExpire(); + } + + + +void DTimestampTestChannel::DoDfcFn() + { + if (!iStarted) + { + iStarted = ETrue; + Kern::QueueRequestComplete(iClient,iStartRequest,KErrNone); + } + else + { + iWaitOnTimerRequest->Data().iDelta = iTimestampDelta; + // PDD will return ETrue here if we have entered LPM + iWaitOnTimerRequest->Data().iLPMEntered = Pdd().EndLPMEntryCheck(); + Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,KErrNone); + } + } + +void DTimestampTestChannel::dfcFn(TAny* aParam) + { + DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam; + pD->DoDfcFn(); + } +