toolsandutils/wintunnel/src_cedar/serialldd.cpp
changeset 0 83f4b4db085c
child 1 d4b442d23379
--- /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);
+	}
+
+