--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolsandutils/wintunnel/src_cedar/serialldd.cpp Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,685 @@
+// Copyright (c) 2002-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/serialldd.cpp
+//
+//
+
+#include "winscomm.h"
+#include <kernel/kern_priv.h>
+#include <e32hal.h>
+#include <e32uid.h>
+
+_LIT(KLddName,"Comm");
+
+
+enum TPanic
+ {
+ ESetConfigWhileRequestPending,
+ ESetSignalsSetAndClear,
+ EResetBuffers,
+ ESetReceiveBufferLength,
+ };
+
+
+inline TUint32 SafeSwap(TUint32 aNewValue, TUint32& aWord)
+ { return (TUint32)NKern::SafeSwap((TAny*)aNewValue, (TAny*&)aWord); }
+
+DECLARE_STANDARD_LDD()
+ {
+ return new DDeviceComm;
+ }
+
+
+DDeviceComm::DDeviceComm()
+ {
+ iParseMask = KDeviceAllowAll;
+ iUnitsMask = 0xffffffff; // Leave units decision to the PDD
+ iVersion = TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+ }
+
+TInt DDeviceComm::Install()
+ {
+ return(SetName(&KLddName));
+ }
+
+void DDeviceComm::GetCaps(TDes8& aDes) const
+ {
+ TPckgBuf<TCapsDevCommV01> b;
+ b().version = TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+ Kern::InfoCopy(aDes,b);
+ }
+
+TInt DDeviceComm::Create(DLogicalChannelBase*& aChannel)
+ {
+ aChannel = new DChannelComm;
+ return aChannel?KErrNone:KErrNoMemory;
+ }
+
+
+DChannelComm::DChannelComm()
+ :
+ iRxCompleteDfc(DChannelComm::CompleteRxDfc,this,2),
+ iTxCompleteDfc(DChannelComm::CompleteTxDfc,this,2),
+ iRxDataAvailableDfc(DChannelComm::RxDataAvailableDfc,this,2),
+ iSigNotifyDfc(DChannelComm::SignalNotifyDfc,this,2),
+// iTurnaroundMinMilliSeconds(0),
+// iTurnaroundTimerRunning(EFalse),
+// iTurnaroundTransmitDelayed(EFalse),
+ iTurnaroundTimer(DChannelComm::TurnaroundStartDfc, this),
+ iTurnaroundDfc(DChannelComm::TurnaroundTimeout, this, 2)
+// iTurnaroundTxDesPtr(0),
+// iTurnaroundTxDesLength(0)
+ {
+ iConfig.iRate = EBps9600;
+ iConfig.iDataBits = EData8;
+ iConfig.iStopBits = EStop1;
+ iConfig.iParity = EParityNone;
+ iConfig.iHandshake = KConfigObeyCTS;
+ iConfig.iParityError = KConfigParityErrorFail;
+ iConfig.iFifo = EFifoEnable;
+ iConfig.iTerminatorCount = 0;
+ iConfig.iXonChar = 0x11;
+ iConfig.iXoffChar = 0x13;
+ iConfig.iSIREnable = ESIRDisable;
+
+ iTxError = KErrNone;
+ iRxError = KErrNone;
+ iRxDAError = KErrNone;
+ iSignalError = KErrNone;
+ iClientDestPtr = 0;
+ iClientSignalResultPtr = 0;
+ iClient = &Kern::CurrentThread();
+ iClient->Open();
+ }
+
+
+DChannelComm::~DChannelComm()
+ {
+ Kern::SafeClose((DObject*&)iClient, NULL);
+ }
+
+void DChannelComm::Shutdown()
+ {
+ // clean-up...
+ if (iStatus == EActive)
+ Stop(EStopPwrDown); // stop PDD
+
+ Complete(EAll, KErrAbort);
+
+ iRxCompleteDfc.Cancel();
+ iTxCompleteDfc.Cancel();
+ iTurnaroundTimer.Cancel();
+ iTurnaroundDfc.Cancel();
+ iSigNotifyDfc.Cancel();
+ iRxDataAvailableDfc.Cancel();
+ }
+
+TInt DChannelComm::TurnaroundSet(TUint aNewTurnaroundMilliSeconds)
+ {
+ TInt r = KErrNone;
+ (void)TurnaroundStopTimer();
+ iTurnaroundMinMilliSeconds = aNewTurnaroundMilliSeconds;
+ return r;
+ }
+
+TBool DChannelComm::TurnaroundStopTimer()
+// Stop the timer and DFC
+ {
+ TInt irq = 0;
+ irq = NKern::DisableInterrupts(1);
+ TBool result = iTurnaroundTimerRunning;
+ if(result)
+ {
+ iTurnaroundTimerRunning = EFalse;
+ iTurnaroundTimer.Cancel();
+ iTurnaroundDfc.Cancel();
+ }
+ NKern::RestoreInterrupts(irq);
+ return result;
+ }
+
+TInt DChannelComm::TurnaroundClear()
+// Clear any old timer
+// Called for any change: from T > 0 to T == 0 or (T = t1 > 0) to (T = t2 > 0)
+// POLICY: If a write has already been delayed, it will be started immediately (next reschedule)
+ {
+ TInt r = KErrNone;
+
+ if(TurnaroundStopTimer())
+ {
+ // if a write is waiting, start a DFC to run it
+ TurnaroundStartDfcImplementation(EFalse);
+ }
+
+ iTurnaroundMinMilliSeconds = 0;
+ return r;
+ }
+
+void DChannelComm::TurnaroundStartDfc(TAny* aSelf)
+ {
+ DChannelComm* self = (DChannelComm*)aSelf;
+ self->TurnaroundStartDfcImplementation(ETrue);
+ }
+
+void DChannelComm::TurnaroundStartDfcImplementation(TBool inIsr)
+ {
+ TInt irq = 0;
+ if(!inIsr)
+ {
+ irq = NKern::DisableInterrupts(1);
+ }
+ iTurnaroundTimerRunning = EFalse;
+ if(iTurnaroundTransmitDelayed)
+ {
+ if(inIsr)
+ iTurnaroundDfc.Add();
+ else
+ {
+ NKern::RestoreInterrupts(irq);
+ iTurnaroundDfc.Enque();
+ }
+ return;
+ }
+ if(!inIsr)
+ {
+ NKern::RestoreInterrupts(irq);
+ }
+ }
+
+void DChannelComm::TurnaroundTimeout(TAny* aSelf)
+ {
+ DChannelComm* self = (DChannelComm*)aSelf;
+ self->TurnaroundTimeoutImplementation();
+ }
+
+void DChannelComm::TurnaroundTimeoutImplementation(void)
+ {
+ TInt irq = NKern::DisableInterrupts(1);
+ if(iTurnaroundTransmitDelayed)
+ {
+ iTurnaroundTransmitDelayed = EFalse; // protected -> prevent reentrant ISR
+ NKern::RestoreInterrupts(irq);
+ if (iStatus==EClosed)
+ {
+ iTurnaroundTxDesPtr = 0;
+ iTurnaroundTxDesLength = 0;
+ Complete(ETx,KErrNotReady);
+ return;
+ }
+
+ // fail signals checked in the PDD
+ InitiateWrite(iTurnaroundTxDesPtr, iTurnaroundTxDesLength);
+ iTurnaroundTxDesPtr = 0;
+ iTurnaroundTxDesLength = 0;
+ }
+ else
+ NKern::RestoreInterrupts(irq);
+ }
+
+TInt DChannelComm::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion &aVer)
+ {
+ if(!Kern::CurrentThreadHasCapability(ECapabilityCommDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by ECOMM.LDD (Comm Driver)")))
+ return KErrPermissionDenied;
+ if (!Kern::QueryVersionSupported(TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber),aVer))
+ return KErrNotSupported;
+
+ // set up the correct DFC queue
+ SetDfcQ(((DComm*)iPdd)->DfcQ(aUnit));
+ iRxCompleteDfc.SetDfcQ(iDfcQ);
+ iTxCompleteDfc.SetDfcQ(iDfcQ);
+ iRxDataAvailableDfc.SetDfcQ(iDfcQ);
+ iSigNotifyDfc.SetDfcQ(iDfcQ);
+ iTurnaroundDfc.SetDfcQ(iDfcQ);
+ iMsgQ.Receive();
+
+ ((DComm *)iPdd)->iLdd = this;
+
+ //setup the initial port configuration
+ PddConfigure(iConfig);
+
+ return KErrNone;
+ }
+
+
+
+
+void DChannelComm::Start()
+ {
+ if (iStatus != EClosed)
+ {
+ PddStart();
+ iStatus = EActive;
+ }
+ }
+
+
+
+
+void DChannelComm::HandleMsg(TMessageBase* aMsg)
+ {
+ TThreadMessage& m = *(TThreadMessage*)aMsg;
+ TInt id = m.iValue;
+ if (id == (TInt)ECloseMsg)
+ {
+ Shutdown();
+ iStatus = EClosed;
+ m.Complete(KErrNone, EFalse);
+ return;
+ }
+ else if (id == KMaxTInt)
+ {
+ // DoCancel
+ DoCancel(m.Int0());
+ m.Complete(KErrNone, ETrue);
+ return;
+ }
+
+ if (id < 0)
+ {
+ // DoRequest
+ TRequestStatus* pS = (TRequestStatus*)m.Ptr0();
+ TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+ if (r != KErrNone)
+ Kern::RequestComplete(iClient, pS, r);
+ m.Complete(KErrNone, ETrue);
+ }
+ else
+ {
+ // DoControl
+ TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
+ m.Complete(r, ETrue);
+ }
+ }
+
+
+TInt DChannelComm::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+ {
+
+ //
+ // First check if we have started
+ //
+ if (iStatus == EOpen)
+ {
+ Start();
+ }
+
+ // Now we can dispatch the request
+ TInt r = KErrNone;
+ TInt len = 0;
+ switch (aReqNo)
+ {
+ case RBusDevComm::ERequestRead:
+ if (a2)
+ //get the size of the client data
+ r = Kern::ThreadRawRead(iClient, a2, &len, sizeof(len));
+ if (r == KErrNone)
+ {
+ if (a1) //doing a read
+ {
+ iRxStatus = aStatus;
+ //start the read
+ InitiateRead(a1,len);
+ }
+ else //notify read data availiable
+ {
+ iRxDAStatus = aStatus;
+ NotifyReadDataAvailable();
+ }
+ }
+ break;
+
+ case RBusDevComm::ERequestWrite:
+ {
+ if (iStatus == EClosed)
+ return KErrNotReady;
+ if (!a1)
+ a1 = (TAny*)1;
+ r = Kern::ThreadRawRead(iClient, a2, &len, sizeof(len)); //get the length of the data to write
+ if (r == KErrNone)
+ {
+ iTxStatus = aStatus;
+ TInt irq = NKern::DisableInterrupts(1);
+ if(iTurnaroundTimerRunning)
+ {
+ iTurnaroundTransmitDelayed = ETrue;
+ iTurnaroundTxDesPtr = a1;
+ iTurnaroundTxDesLength = len;
+ NKern::RestoreInterrupts(irq);
+ }
+ else
+ {
+ NKern::RestoreInterrupts(irq);
+ InitiateWrite(a1, len); //a1 is ptr to data to write (on client side)
+ }
+ }
+ break;
+ }
+
+ case RBusDevComm::ERequestNotifySignalChange:
+ {
+ //a1 has place to put the result
+ //a2 has the signal mask
+ if (!a1)
+ {
+ r = KErrArgument;
+ break;
+ }
+
+ //start the signal request
+ TInt mask = 0;
+ r = Kern::ThreadRawRead(iClient, a2, &mask, sizeof(mask)); //get the signal mask
+ if (r == KErrNone)
+ {
+ iSignalStatus = aStatus;
+ InitiateNotifySignals(a1, mask);
+ }
+ break;
+ }
+
+
+ case RBusDevComm::ERequestBreak:
+ Complete(aReqNo, KErrNotSupported);
+ break;
+
+ default:
+ r = KErrNotSupported;
+ break;
+
+ }
+ return r;
+ }
+
+TInt DChannelComm::SetConfig(TCommConfigV01& c)
+ {
+ iConfig = c;
+ PddConfigure(iConfig);
+ return KErrNone;
+ }
+
+TInt DChannelComm::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+ {
+
+ TCommConfigV01 c;
+ TInt r = KErrNone;
+
+ switch (aFunction)
+ {
+ case RBusDevComm::EControlConfig:
+ {
+ //get the current configuration
+ TPtrC8 cfg((const TUint8*)&iConfig, sizeof(iConfig));
+ r = Kern::ThreadDesWrite(iClient, a1, cfg, 0, KTruncateToMaxLength, iClient);
+ break;
+ }
+
+ case RBusDevComm::EControlSetConfig:
+ {
+ if (AreAnyPending())
+ Kern::PanicCurrentThread(_L("D32COMM"), ESetConfigWhileRequestPending);
+ else
+ {
+ memclr(&c, sizeof(c));
+ TPtr8 cfg((TUint8*)&c, 0, sizeof(c));
+ r = Kern::ThreadDesRead(iClient, a1, cfg, 0, 0);
+ if (r == KErrNone)
+ r = SetConfig(c); //set the new configuration
+ }
+ break;
+ }
+
+ case RBusDevComm::EControlCaps:
+ {
+ //get capabilities
+ TCommCaps2 caps;
+ PddCaps(caps); //call ipdd->Caps
+ r = Kern::ThreadDesWrite(iClient, a1, caps, 0, KTruncateToMaxLength, iClient);
+ break;
+ }
+
+ case RBusDevComm::EControlSignals:
+ {
+ r = Signals();
+ break;
+ }
+
+ case RBusDevComm::EControlSetSignals:
+ {
+// if (((TUint)a1)&((TUint)a2)) //can't set and clear at same time
+// {
+// Kern::PanicCurrentThread(_L("D32COMM"), ESetSignalsSetAndClear);
+// }
+// else
+ {
+
+ SetSignals((TUint)a1, (TUint)a2);
+ }
+ break;
+ }
+
+ case RBusDevComm::EControlQueryReceiveBuffer:
+ r = RxCount();
+ break;
+
+ case RBusDevComm::EControlResetBuffers:
+ if (AreAnyPending())
+ Kern::PanicCurrentThread(_L("D32COMM"), EResetBuffers);
+ else
+ ResetBuffers(ETrue);
+ break;
+
+ case RBusDevComm::EControlReceiveBufferLength:
+ r = RxBufferSize();
+ break;
+
+ case RBusDevComm::EControlSetReceiveBufferLength:
+ if (AreAnyPending())
+ Kern::PanicCurrentThread(_L("D32COMM"), ESetReceiveBufferLength);
+ else
+ r = SetRxBufferSize((TInt)a1);
+ break;
+
+ case RBusDevComm::EControlMinTurnaroundTime:
+ r = iTurnaroundMicroSeconds; // used saved value
+ break;
+
+ case RBusDevComm::EControlSetMinTurnaroundTime:
+ {
+ if ((TInt)a1<0)
+ a1=(TAny*)0;
+ iTurnaroundMicroSeconds = (TUint)a1; // save this
+ TUint newTurnaroundMilliSeconds = (TUint)a1/1000; // convert to ms
+ if(newTurnaroundMilliSeconds != iTurnaroundMinMilliSeconds)
+ {
+ // POLICY: if a new turnaround time is set before the previous running timer has expired and a
+ // write request has been queued, the transmission goes ahead immediately
+ TurnaroundClear();
+ if(newTurnaroundMilliSeconds > 0)
+ {
+ r = TurnaroundSet(newTurnaroundMilliSeconds);
+ }
+ }
+ }
+ break;
+
+ default:
+ r = KErrNotSupported;
+ }
+ return(r);
+ }
+
+
+void DChannelComm::SignalNotifyDfc(TAny* aPtr)
+ {
+ DChannelComm* pC = (DChannelComm*)aPtr;
+ pC->DoSignalNotify();
+ }
+
+void DChannelComm::RxDataAvailableDfc(TAny* aPtr)
+ {
+ DChannelComm* pC = (DChannelComm*)aPtr;
+ pC->DoRxDataAvailable();
+ }
+
+void DChannelComm::DoRxDataAvailable()
+ {
+ Complete(ERxDA, iRxDAError);
+ iRxDAError = KErrNone;
+ }
+
+void DChannelComm::DoSignalNotify()
+ {
+ //copy the data back to the client
+ if (iSignalError == KErrNone)
+ iSignalError = Kern::ThreadRawWrite(iClient, iClientSignalResultPtr,&iSignalResult, sizeof(iSignalResult), iClient);
+ Complete(ESigChg, iSignalError);
+ iSignalError = KErrNone;
+ }
+
+void DChannelComm::CompleteTxDfc(TAny* aPtr)
+ {
+ DChannelComm* pC = (DChannelComm*)aPtr;
+ pC->DoCompleteTx();
+ }
+
+void DChannelComm::DoCompleteTx()
+ {
+ Complete(ETx, iTxError);
+ iTxError = KErrNone;
+ }
+
+void DChannelComm::CompleteRxDfc(TAny* aPtr)
+ {
+ DChannelComm* pC = (DChannelComm*)aPtr;
+ pC->DoCompleteRx();
+ }
+
+void DChannelComm::DoCompleteRx()
+ {
+ if (iRxError == KErrNone)
+ {
+ //copy the data back to the client
+ iRxError = Kern::ThreadDesWrite(iClient, (TDes8*)iClientDestPtr, *RxBuffer(), 0, KChunkShiftBy0, iClient);
+ }
+ Complete(ERx, iRxError);
+ iRxError = KErrNone;
+ TInt irq = NKern::DisableInterrupts(1);
+ if(iTurnaroundMinMilliSeconds > 0)
+ {
+ // POLICY: if timer is running from a previous read, stop it and re-start it
+ if(iTurnaroundTimerRunning)
+ {
+ iTurnaroundTimer.Cancel();
+ iTurnaroundDfc.Cancel();
+ }
+ iTurnaroundTimerRunning = ETrue;
+ TInt timeout = NKern::TimerTicks(iTurnaroundMinMilliSeconds);
+ iTurnaroundTimer.OneShot(timeout);
+ }
+ NKern::RestoreInterrupts(irq);
+ }
+
+void DChannelComm::DoCancel(TInt aMask)
+ {
+ if (aMask & RBusDevComm::ERequestReadCancel)
+ {
+ ReadCancel();
+ }
+
+ if (aMask & RBusDevComm::ERequestWriteCancel)
+ {
+ TInt irq = NKern::DisableInterrupts(1);
+ if(iTurnaroundTransmitDelayed)
+ {
+ iTurnaroundTxDesPtr = 0;
+ iTurnaroundTxDesLength = 0;
+ iTurnaroundTransmitDelayed = EFalse;
+ }
+ NKern::RestoreInterrupts(irq);
+
+ WriteCancel();
+ }
+
+ if (aMask & RBusDevComm::ERequestNotifySignalChangeCancel)
+ {
+ SignalChangeCancel();
+ Complete(ESigChg,KErrCancel);
+ }
+
+ }
+
+
+void DChannelComm::InitiateWrite(TAny *aTxDes, TInt aLength)
+ {
+
+//aTxDes has client side data
+//aLength has the len
+
+ if (!aTxDes)
+ {
+ Complete(ETx, KErrArgument);
+ return;
+ }
+ // call the pdd to fill its buffer and write the data
+ Write(iClient, aTxDes, aLength);
+ }
+
+void DChannelComm::InitiateRead(TAny *aRxDes, TInt aLength)
+ {
+
+ // Complete zero-length read immediately. maybe not
+
+// if (aLength == 0)
+// {
+// Complete(ERx, KErrNone);
+// return;
+// }
+ TInt max=Kern::ThreadGetDesMaxLength(iClient,aRxDes);
+
+ if (max < Abs(aLength) || max < 0)
+ Complete(ERx, KErrGeneral);
+ // do not start the Turnaround timer (invalid Descriptor this read never starts)
+ else
+ {
+ iClientDestPtr = aRxDes;
+ Read(iClient, aRxDes, aLength);
+ }
+ }
+
+void DChannelComm::InitiateNotifySignals(TAny *aSignalResultPtr, TInt aMask)
+ {
+ //aMask has the mask of signals we require
+ //aSignalResultPtr is a pointer to the clients area for the result
+ iClientSignalResultPtr = (TUint*)aSignalResultPtr;
+ NotifySignals(iClient, aMask);
+ }
+
+void DChannelComm::NotifyReadDataAvailable()
+ {
+ NotifyDataAvailable();
+ }
+
+
+void DChannelComm::Complete(TInt aMask, TInt aReason)
+ {
+ if (aMask & ERx)
+ Kern::RequestComplete(iClient, iRxStatus, aReason);
+ if (aMask & ETx)
+ Kern::RequestComplete(iClient, iTxStatus, aReason);
+ if (aMask & ESigChg)
+ Kern::RequestComplete(iClient, iSignalStatus, aReason);
+ if (aMask & ERxDA)
+ Kern::RequestComplete(iClient, iRxDAStatus, aReason);
+ }
+
+