--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dbgagents/trkagent/dccdriver/TrkDccDriver.cpp Tue Mar 02 10:33:16 2010 +0530
@@ -0,0 +1,553 @@
+/*
+* Copyright (c) 2006 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:
+*
+*/
+
+
+#ifdef __WINS__
+#error - this driver cannot be built for emulation
+#endif
+
+#include <e32def.h>
+#include <e32cmn.h>
+#include <kernel.h>
+#include <kern_priv.h>
+#include <arm.h>
+
+#include "TrkDccComm.h"
+#include "TrkDccDriver.h"
+
+//This macro turns on DCC3 mode, this is always turned on.
+//To test DCC1 mode, comment this out and make sure to configure T32 to use DCC1 as well.
+#define DCC3
+
+//currenly both start and end bytes for the packet are the same
+#define PKT_STRT_BYTE 0x7E
+#define PKT_END_BYTE 0x7E
+
+#define KTrkAppSecurUid 0x200170BB
+#define KTrkExeSecurUid 0x200159E2
+//
+// Static function definitions
+//
+
+
+//
+//
+// DTrkDccDriverFactory implementation
+//
+//
+
+//
+// DTrkDccDriverFactory constructor
+//
+DTrkDccDriverFactory::DTrkDccDriverFactory()
+{
+ iVersion = TVersion(KMajorDccVersionNumber, KMinorDccVersionNumber, KBuildDccVersionNumber);
+}
+
+//
+// DTrkDccDriverFactory::Create
+//
+TInt DTrkDccDriverFactory::Create(DLogicalChannelBase*& aChannel)
+{
+ if (iOpenChannels != 0)
+ return KErrInUse; // a channel is already open
+
+ aChannel = new DTrkDccChannel(this);
+
+ return aChannel ? KErrNone : KErrNoMemory;
+}
+
+//
+// DTrkDccDriverFactory::Install
+//
+TInt DTrkDccDriverFactory::Install()
+{
+ return(SetName(&KTrkDccDriverName));
+}
+
+//
+// DTrkDccDriverFactory::Install
+//
+void DTrkDccDriverFactory::GetCaps(TDes8& aDes) const
+{
+ TCapsTrkDccDriver b;
+ b.iVersion = TVersion(KMajorDccVersionNumber, KMinorDccVersionNumber, KBuildDccVersionNumber);
+
+ Kern::InfoCopy(aDes,(TUint8*)&b, sizeof(b));
+}
+
+
+//
+//
+// DTrkDccChannel implementation
+//
+//
+
+//
+// DTrkDccChannel constructor
+//
+DTrkDccChannel::DTrkDccChannel(DLogicalDevice* aLogicalDevice)
+ : iRxTimer(DTrkDccChannel::RxTimerCallBack, this),
+ iRxBufSize(MAXMESSAGESIZE*2),
+ iRxGetIndx(0),
+ iRxPutIndx(0),
+ iRxCompleteDfc(DTrkDccChannel::RxTimerDfc, this, 2),
+ iInterruptId(76),
+ iPacketStarted(EFalse),
+ iPacketEnded(EFalse)
+
+
+{
+ LOG_MSG("DTrkDccChannel::DTrkDccChannel()");
+
+ iDevice = aLogicalDevice;
+
+ iClientThread = &Kern::CurrentThread();
+ TInt err = iClientThread->Open();
+
+ iRxTimeOut = NKern::TimerTicks(1);
+}
+
+//
+// DTrkDccChannel destructor
+//
+DTrkDccChannel::~DTrkDccChannel()
+{
+ LOG_MSG("DTrkDccChannel::~DTrkDccChannel()");
+
+ iRxTimer.Cancel();
+
+ if (iRxBuffer)
+ {
+ delete iRxBuffer;
+ iRxBuffer = NULL;
+ }
+ if (iLock)
+ iLock->Close(NULL);
+
+ Kern::SafeClose((DObject*&)iClientThread, NULL);
+}
+
+//
+// DTrkDccChannel::DoCreate
+//
+TInt DTrkDccChannel::DoCreate(TInt /*aUnit*/, const TDesC* /*anInfo*/, const TVersion& aVer)
+{
+ LOG_MSG("DTrkDccChannel::DoCreate()");
+
+ if (!Kern::QueryVersionSupported(TVersion(KMajorDccVersionNumber, KMinorDccVersionNumber, KBuildDccVersionNumber), aVer))
+ return KErrNotSupported;
+
+ //Setup the driver for receiving client messages
+ iDFCQue = NULL;
+ TBuf8<KMaxInfoName> dccDFC = _L8("DCC DFC");;
+
+ TInt err = Kern::DfcQCreate(iDFCQue, 27, &dccDFC);
+ if (err == KErrNone)
+ {
+ SetDfcQ(iDFCQue);
+ }
+ else
+ {
+ SetDfcQ(Kern::DfcQue0());
+ }
+
+ iMsgQ.Receive();
+
+ iRxCompleteDfc.SetDfcQ(Kern::TimerDfcQ());
+
+ iRxBuffer=(TUint8*)Kern::Alloc(iRxBufSize);
+
+ err = Kern::SemaphoreCreate(iLock, _L("TrkDccDriverWriteLock"), 1 /* Initial count */);
+ if (err != KErrNone)
+ return err;
+
+ return KErrNone;
+}
+
+//
+// DTrkDccChannel::DoCancel
+//
+void DTrkDccChannel::DoCancel(TInt aReqNo)
+{
+ LOG_MSG("DTrkDccChannel::DoCancel()");
+
+ switch(aReqNo)
+ {
+ case RTrkDccDriver::ERequestReadCancel:
+ {
+ Kern::RequestComplete(iClientThread, iRxRequestStatus, KErrCancel);
+ iRxClientBuffer = NULL;
+ iRxRequestStatus = NULL;
+ iRxClientBufferLength = 0;
+
+ iRxTimer.Cancel();
+ }
+ break;
+ }
+
+}
+
+//
+// DTrkDccChannel::DoRequest
+//
+void DTrkDccChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+{
+ LOG_MSG("DTrkDccChannel::DoRequest()");
+
+ switch(aReqNo)
+ {
+ case RTrkDccDriver::ERequestRead:
+ {
+ iRxRequestStatus = aStatus;
+ iRxClientBuffer = a1;
+ iRxClientBufferLength = (TUint32)a2;
+ //start the polling timer...
+ iRxTimer.OneShot(iRxTimeOut);
+ break;
+ }
+ default:
+ Kern::RequestComplete(iClientThread, aStatus, KErrNotSupported);
+ }
+}
+
+//
+// DTrkDccChannel::DoControl
+//
+TInt DTrkDccChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+{
+ LOG_MSG("DTrkDccChannel::DoControl()");
+
+ TInt err = KErrNone;
+
+ switch(aFunction)
+ {
+ case RTrkDccDriver::EControlWrite:
+ {
+ //lock the Semaphore so that write doesn't happen when a write is already in progress.
+ Kern::SemaphoreWait(*iLock);
+ err = DoWrite((TUint32)a1, a2);
+ Kern::SemaphoreSignal(*iLock);
+ break;
+ }
+ default:
+ {
+ return KErrGeneral;
+ }
+
+ }
+ if (KErrNone != err)
+ {
+ LOG_MSG2("Error %d from control function", err);
+ }
+ return err;
+}
+
+//
+// DTrkDccChannel::HandleMsg
+//
+void DTrkDccChannel::HandleMsg(TMessageBase* aMsg)
+{
+ LOG_MSG("DTrkDccChannel::HandleMsg()");
+
+ TThreadMessage& m = *(TThreadMessage*)aMsg;
+ TInt id = m.iValue;
+
+
+ if (id == (TInt)ECloseMsg)
+ {
+ m.Complete(KErrNone, EFalse);
+ return;
+ }
+
+ if (id == KMaxTInt)
+ {
+ // DoCancel
+ DoCancel(m.Int0());
+ m.Complete(KErrNone, ETrue);
+ return;
+ }
+
+ if (id < 0)
+ {
+ // DoRequest
+ TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0();
+ DoRequest(~id, pStatus, m.Ptr1(), m.Ptr2());
+ m.Complete(KErrNone, ETrue);
+ }
+ else
+ {
+ // DoControl
+ TInt err = DoControl(id, m.Ptr0(), m.Ptr1());
+ m.Complete(err, ETrue);
+ }
+}
+
+//
+// DTrkDccChannel::DoWrite
+//
+TInt DTrkDccChannel::DoWrite(TUint32 aLength, TAny* a2)
+{
+ LOG_MSG("DTrkDccChannel::DoWrite()");
+
+ TInt err = KErrNone;
+
+ err = Kern::ThreadDesRead(iClientThread, a2, iTxBuffer, 0, KChunkShiftBy0);
+
+ if (err == KErrNone)
+ {
+ err = WriteDccChannel(iTxBuffer);
+ }
+ return err;
+}
+
+//
+// DTrkDccChannel::DoRead
+//
+TInt DTrkDccChannel::DoRead()
+{
+ TInt err = KErrNone;
+
+ ReadDccChannel();
+
+ if (iRxPutIndx != iRxGetIndx)
+ {
+ if (iPacketEnded)
+ {
+ iPacketStarted = EFalse;
+ iPacketEnded = EFalse;
+ }
+ //there is some data, complete the read request if there is one pending
+ DoCompleteRx();
+
+ if (iRxPutIndx == iRxGetIndx)
+ {
+ iRxPutIndx = iRxGetIndx = 0;
+ }
+ }
+ else
+ {
+ err = -1;
+ //start the timer again since we didn't complete the request
+ iRxTimer.OneShot(iRxTimeOut);
+ }
+
+ return err;
+}
+
+//
+// DTrkDccChannel::WriteDccChannel
+//
+// This function writes all the data in the descriptor word by word.
+// DCC3 mode is used for transferring the data to the DCC channel.
+// With DCC3, the number of bytes in the word is encoded in its MSB.
+// DCC3 mode can be turned of by commenting the DCC3 macro at the
+// beginning of this file.
+//
+TInt DTrkDccChannel::WriteDccChannel(const TDesC8& aDes)
+{
+ TInt err = KErrNone;
+
+ const TText8* pStart = aDes.Ptr();
+ const TText8* pEnd = pStart + aDes.Length();
+ if (pStart != pEnd)
+ {
+ while (pStart < pEnd)
+ {
+ TUint retries = 10;
+
+ #ifdef DCC3
+ TUint32 data = 0;
+ //for DCC3 support
+ if ((pEnd-pStart) >= 3)
+ {
+ data = ((TUint32)(*pStart++)) | ((TUint32)(*pStart++))<<8 | ((TUint32)(*pStart++))<<16 | (0x02<<24);
+ }
+ else if ((pEnd-pStart) == 2)
+ {
+ data = ((TUint32)(*pStart++)) | ((TUint32)(*pStart++))<<8 | (0x01<<24);
+ }
+ else if ((pEnd-pStart) == 1)
+ {
+ data = (TUint32)(*pStart++);
+ }
+ #endif
+
+ while (retries--)
+ {
+ #ifdef DCC3
+ err = Arm::DebugOutJTAG(data);
+ #else
+ err = Arm::DebugOutJTAG(*pStart);
+ #endif
+
+ //if we get timeout error, try three times sending the same byte
+ if (err == KErrTimedOut)
+ {
+ LOG_MSG("Write timed out, trying again\n");
+ continue;
+ }
+ else
+ break;
+ }
+ if (err)
+ {
+ LOG_MSG2("WriteDccChannel() failed %d", err);
+ return err;
+ }
+
+ #ifndef DCC3
+ pStart++;
+ #endif
+
+ }
+ }
+ return err;
+}
+
+//
+// DTrkDccChannel::ReadDccChannel
+//
+// Strictly reads packet by packets since TRK expects the host debugger
+// to wait for the response for the cmd sent.
+// This function will return if
+// - the packet is completely read
+// - if out of band data, i.e. data not conforming to TRK protocol packets
+// - if an error other than KErrNotReady happens in while in the middle of
+// reading a packet.
+// Also the function uses DCC3 mode, where the no of bytes sent in the word
+// is encoded in the MSB and the actual data bytes in the remaining bytes.
+// Like for sending three bytes, the word will be 0x02CCBBAA.
+// For sending three bytes, the MSB should be 2.
+// For two bytes, the MSB should be 1.
+// For one bytes, the MSB should be 0.
+//
+void DTrkDccChannel::ReadDccChannel()
+{
+ TInt err = KErrNone;
+ TInt err1 = KErrNone;
+
+ TUint i = iRxPutIndx;
+ TUint32 data;
+
+ err = err1 = Arm::DebugInJTAG(data);
+ while (KErrNone == err)
+ {
+ if (KErrNone == err1)
+ {
+ TUint8 nBytes = 0;
+ nBytes = TUint8(data>>24);
+
+ for (int j=0; j<=nBytes; j++)
+ {
+ iRxBuffer[i] = (TUint8)(data>>(j*8));
+ if (iRxBuffer[i] == PKT_STRT_BYTE)
+ {
+ if (!iPacketStarted)
+ {
+ iPacketStarted = ETrue;
+ }
+ else
+ {
+ iPacketEnded = ETrue;
+ }
+ }
+ i++; //increment i here so that put index can be appriopriately set later
+ }
+
+ if (i == iRxBufSize)
+ {
+ i = 0;
+ break;
+ }
+ //if cmd packet ended, send the data to the engine.
+ if (iPacketEnded)
+ {
+ break;
+ }
+ }
+
+ //read again to see if there is data already available
+ err = err1 = Arm::DebugInJTAG(data);
+
+ //if the packet is started, try to read the whole packet
+ //so set the err value to KErrNone so that we can continue reading
+ if ((err == KErrNotReady) && iPacketStarted && !iPacketEnded)
+ err = KErrNone;
+
+ if (err != KErrNone && err != KErrNotReady)
+ LOG_MSG2("Read Error %d\n", err);
+ }
+
+ iRxPutIndx=i;
+}
+
+//
+// DTrkDccChannel::RxTimerCallBack
+//
+void DTrkDccChannel::RxTimerCallBack(TAny* aPtr)
+{
+ // called from ISR when timer completes
+ DTrkDccChannel *pChannel = (DTrkDccChannel*)aPtr;
+ pChannel->iRxCompleteDfc.Add();
+}
+
+//
+// DTrkDccChannel::RxTimerDfc
+//
+void DTrkDccChannel::RxTimerDfc(TAny* aPtr)
+{
+ DTrkDccChannel *pChannel = (DTrkDccChannel*)aPtr;
+ pChannel->DoRead();
+}
+
+//
+// DTrkDccChannel::DoCompleteRx
+//
+void DTrkDccChannel::DoCompleteRx()
+{
+ LOG_MSG("DTrkDccChannel::DoCompleteRx()");
+
+ if (iRxRequestStatus)
+ {
+ TInt avail = 0;
+ if (iRxPutIndx > iRxGetIndx)
+ avail = iRxPutIndx-iRxGetIndx;
+ else
+ avail = iRxBufSize-iRxGetIndx;
+
+ TInt len = Min(avail, iRxClientBufferLength);
+
+ TPtrC8 des(iRxBuffer+iRxGetIndx, len);
+
+ TInt err = Kern::ThreadDesWrite(iClientThread, iRxClientBuffer, des, 0, KChunkShiftBy0, iClientThread);
+
+ Kern::RequestComplete(iClientThread, iRxRequestStatus, err);
+
+ iRxRequestStatus = NULL;
+ iRxGetIndx += len;
+ }
+
+ if (iRxGetIndx >= iRxBufSize)
+ iRxGetIndx = 0;
+}
+
+
+DECLARE_STANDARD_LDD()
+{
+ return new DTrkDccDriverFactory;
+}