--- /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 <kern_priv.h>
+#include <kernel.h>
+#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();
+ }
+