kernel/eka/drivers/ecomm/d_comm.cpp
changeset 0 a41df078684a
child 167 b41fc9c39ca7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/ecomm/d_comm.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2165 @@
+// Copyright (c) 1995-2009 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:
+// e32\drivers\ecomm\d_comm.cpp
+// 
+//
+
+#include <drivers/comm.h>
+#include <kernel/kern_priv.h>
+#include <e32hal.h>
+#include <e32uid.h>
+
+// Logging
+#define LOG_ON(x) Kern::Printf##x
+#define LOG_OFF(x)
+#define LOG		LOG_OFF
+
+
+//#define __UART_RX_ERROR(x)    *(TUint*)0xfeedface=(x)
+//#define __OVERRUN() *(TUint*)0xfaece5=0
+
+#define __UART_RX_ERROR(x)
+#define __OVERRUN()
+
+_LIT(KLddName,"Comm");
+
+
+const TUint KXoffSignal=0x80;
+//
+const TUint KBreaking=0x02;
+const TUint KBreakPending=0x04;
+//
+enum TPanic
+	{
+	ESetConfigWhileRequestPending,
+	ESetSignalsSetAndClear,
+	EResetBuffers,
+	ESetReceiveBufferLength,
+	};
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DDeviceComm;
+	}
+
+DDeviceComm::DDeviceComm()
+//
+// Constructor
+//
+	{
+	LOG(("DDeviceComm::DDeviceComm"));
+	iParseMask=KDeviceAllowAll;
+	iUnitsMask=0xffffffff; // Leave units decision to the PDD
+	iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+	}
+
+TInt DDeviceComm::Install()
+//
+// Install the device driver.
+//
+	{
+	LOG(("DDeviceComm::Install"));
+	return(SetName(&KLddName));
+	}
+
+void DDeviceComm::GetCaps(TDes8& aDes) const
+//
+// Return the Comm capabilities.
+//
+	{
+	LOG(("DDeviceComm::GetCaps"));
+	TPckgBuf<TCapsDevCommV01> b;
+	b().version=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+	Kern::InfoCopy(aDes,b);
+	}
+
+TInt DDeviceComm::Create(DLogicalChannelBase*& aChannel)
+//
+// Create a channel on the device.
+//
+	{
+	LOG(("DDeviceComm::Create"));
+	aChannel=new DChannelComm;
+	return aChannel?KErrNone:KErrNoMemory;
+	}
+
+DChannelComm::DChannelComm()
+//
+// Constructor
+//
+	:	iPowerUpDfc(DChannelComm::PowerUpDfc,this,3),
+		iPowerDownDfc(DChannelComm::PowerDownDfc,this,3),
+		iRxDrainDfc(DChannelComm::DrainRxDfc,this,2),
+		iRxCompleteDfc(DChannelComm::CompleteRxDfc,this,2),
+		iTxFillDfc(DChannelComm::FillTxDfc,this,2),
+		iTxCompleteDfc(DChannelComm::CompleteTxDfc,this,2),
+		iTimerDfc(DChannelComm::TimerDfcFn,this,3),
+		iSigNotifyDfc(DChannelComm::SigNotifyDfc,this,2),
+//		iTurnaroundMinMilliSeconds(0),
+//		iTurnaroundTimerRunning(EFalse),
+//		iTurnaroundTransmitDelayed(EFalse),
+		iTurnaroundTimer(DChannelComm::TurnaroundStartDfc, this),
+		iTurnaroundDfc(DChannelComm::TurnaroundTimeout, this, 2),
+		iTimer(DChannelComm::MsCallBack,this),
+		iBreakDfc(DChannelComm::FinishBreakDfc, this, 2),
+		iLock(TSpinLock::EOrderGenericIrqLow3)
+	{
+	LOG(("DChannelComm"));
+//
+// Setup the default config
+//
+	iConfig.iRate=EBps9600;
+	iConfig.iDataBits=EData8;
+	iConfig.iStopBits=EStop1;
+	iConfig.iParity=EParityNone;
+	iConfig.iFifo=EFifoEnable;
+	iConfig.iHandshake=KConfigObeyCTS;
+	iConfig.iParityError=KConfigParityErrorFail;
+	iConfig.iSIREnable=ESIRDisable;
+//	iConfig.iTerminatorCount=0;
+//	iConfig.iTerminator[0]=0;
+//	iConfig.iTerminator[1]=0;
+//	iConfig.iTerminator[2]=0;
+//	iConfig.iTerminator[3]=0;
+	iConfig.iXonChar=0x11; // XON
+	iConfig.iXoffChar=0x13; // XOFF
+//	iConfig.iSpecialRate=0;
+//	iConfig.iParityErrorChar=0;
+	iRxXonChar=0xffffffff;
+	iRxXoffChar=0xffffffff;
+	iStatus=EOpen;
+//	iFlags=0;
+//	iSignals=0;
+//	iFailSignals=0;
+//	iHoldSignals=0;
+//	iFlowControlSignals=0;
+//	iAutoSignals=0;
+//	iTerminatorMask[0...31]=0;
+//	iShutdown=EFalse;
+//	iRxCharBuf=NULL;
+//	iRxErrorBuf=NULL;
+//	iRxPutIndex=0;
+//	iRxGetIndex=0;
+//	iRxBufSize=0;
+//	iFlowControlLowerThreshold=0;
+//	iFlowControlUpperThreshold=0;
+//	iRxDrainThreshold=0;
+//	iRxBufCompleteIndex=0;
+//	iInputHeld=EFalse;
+//	iRxClientBufReq=NULL;
+//	iRxDesPos=0;
+//	iRxLength=0;
+//	iRxOutstanding=EFalse;
+//	iRxError=KErrNone;
+//	iTxBuffer=NULL;
+//	iTxPutIndex=0;
+//	iTxGetIndex=0;
+//	iTxBufSize=0;
+//	iTxFillThreshold=0;
+	iOutputHeld=0;
+	iJamChar=KTxNoChar;
+//	iTxDesPtr=NULL;
+//	iTxDesPos=0;
+//	iTxDesLength=0;
+//	iTxOutstanding=EFalse;
+//	iTxError=KErrNone;
+
+//	iTimeout=10;
+	iTimeout=NKern::TimerTicks(5);
+	iClient=&Kern::CurrentThread();
+	iClient->Open();
+//	iSigNotifyMask=0;
+//	iSignalsPtr=NULL;
+//	iSigNotifyStatus=NULL;
+	iBreakStatus=NULL;
+	iNotifiedSignals=0xffffffff;
+	iPinObjSetConfig=NULL;
+	}
+
+DChannelComm::~DChannelComm()
+//
+// Destructor
+//
+	{
+	LOG(("~DChannelComm"));
+	if (iPowerHandler)
+		{
+		iPowerHandler->Remove(); 
+		delete iPowerHandler;
+		}
+    if (iRxCharBuf)
+        Kern::Free(iRxCharBuf);
+    if (iTxBuffer)
+        Kern::Free(iTxBuffer);
+	if (iBreakStatus)
+		Kern::DestroyClientRequest(iBreakStatus);
+	if (iSignalsReq)
+		Kern::DestroyClientRequest(iSignalsReq);
+	if (iPinObjSetConfig)
+		Kern::DestroyVirtualPinObject(iPinObjSetConfig);
+	Kern::SafeClose((DObject*&)iClient, NULL);
+	}
+
+
+void DChannelComm::Complete(TInt aMask, TInt aReason)
+	{
+	LOG(("Complete(aMask=%x aReason=%d)", aMask, aReason));
+	if (aMask & ERx)
+		iRxBufReq.Complete(iClient, aReason);
+	if (aMask & ETx)
+		iTxBufReq.Complete(iClient, aReason);
+	if (aMask & ESigChg)
+		Kern::QueueRequestComplete(iClient, iSignalsReq, aReason);
+	if ((aMask & EBreak) && iBreakStatus && iBreakStatus->IsReady())
+		Kern::QueueRequestComplete(iClient, iBreakStatus, aReason);
+	}
+
+TInt DChannelComm::Shutdown()
+	{
+	__KTRACE_OPT(KPOWER,Kern::Printf("DChannelComm::Shutdown()"));
+	LOG(("Shutdown()"));
+
+    if (iStatus == EActive)
+        Stop(EStopPwrDown);
+
+    Complete(EAll, KErrAbort);
+
+	// UART interrupts are disabled; must make sure DFCs are not queued.
+	iRxDrainDfc.Cancel();
+	iRxCompleteDfc.Cancel();
+	iTxFillDfc.Cancel();
+	iTxCompleteDfc.Cancel();
+	iTimer.Cancel();
+	iTurnaroundTimer.Cancel();
+	iTurnaroundDfc.Cancel();
+	iTimerDfc.Cancel();
+	iSigNotifyDfc.Cancel();
+	iPowerUpDfc.Cancel();
+	iPowerDownDfc.Cancel();
+	iBreakTimer.Cancel();
+	iBreakDfc.Cancel();
+	
+	if (iPdd)
+		SetSignals(0,iFlowControlSignals|iAutoSignals);
+
+	return KErrCompletion;
+	}
+
+TInt DChannelComm::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion &aVer)
+//
+// Create the channel from the passed info.
+//
+	{
+	LOG(("DoCreate(aUnit=%d,...)", aUnit));
+	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));
+	iPowerUpDfc.SetDfcQ(iDfcQ);
+	iPowerDownDfc.SetDfcQ(iDfcQ);
+	iRxDrainDfc.SetDfcQ(iDfcQ);
+	iRxCompleteDfc.SetDfcQ(iDfcQ);
+	iTxFillDfc.SetDfcQ(iDfcQ);
+	iTxCompleteDfc.SetDfcQ(iDfcQ);
+	iTimerDfc.SetDfcQ(iDfcQ);
+	iSigNotifyDfc.SetDfcQ(iDfcQ);
+	iTurnaroundDfc.SetDfcQ(iDfcQ);
+	iBreakDfc.SetDfcQ(iDfcQ);
+	iMsgQ.Receive();
+
+	// initialise the TX buffer
+	iTxBufSize=KTxBufferSize;
+	iTxBuffer=(TUint8*)Kern::Alloc(iTxBufSize);
+	if (!iTxBuffer)
+		return KErrNoMemory;
+	iTxFillThreshold=iTxBufSize>>1;
+
+	// initialise the RX buffer
+	iRxBufSize=KDefaultRxBufferSize;
+	iRxCharBuf=(TUint8*)Kern::Alloc(iRxBufSize<<1);
+	if (!iRxCharBuf)
+		return KErrNoMemory;
+	iRxErrorBuf=iRxCharBuf+iRxBufSize;
+	iFlowControlLowerThreshold=iRxBufSize>>2;
+	iFlowControlUpperThreshold=3*iRxBufSize>>2;
+	iRxDrainThreshold=iRxBufSize>>1;
+
+	// Create request objects
+	TInt r = Kern::CreateClientDataRequest(iSignalsReq);
+	if (r==KErrNone)
+		r = Kern::CreateClientRequest(iBreakStatus);
+	if (r==KErrNone)
+		r = iRxBufReq.Create();
+	if (r==KErrNone)
+		r = iTxBufReq.Create();
+	if (r==KErrNone)
+		r = Kern::CreateVirtualPinObject(iPinObjSetConfig);
+	if (r != KErrNone)
+		return r;
+
+	((DComm *)iPdd)->iLdd=this;
+	PddCheckConfig(iConfig);
+	iFailSignals=FailSignals(iConfig.iHandshake);
+	iHoldSignals=HoldSignals(iConfig.iHandshake);
+	iFlowControlSignals=FlowControlSignals(iConfig.iHandshake);
+	iAutoSignals=AutoSignals(iConfig.iHandshake);
+
+	// create the power handler
+	iPowerHandler=new DCommPowerHandler(this);
+	if (!iPowerHandler)
+		return KErrNoMemory;
+	iPowerHandler->Add();
+	DoPowerUp();
+
+	return KErrNone;
+	}
+
+TInt DChannelComm::RequestUserHandle(DThread* aThread, TOwnerType aType)
+	{
+	// Ensure that each channel can only be used by a single thread.
+	return (aThread!=iClient) ?  KErrAccessDenied : KErrNone;
+	}
+
+void DChannelComm::MsCallBack(TAny* aPtr)
+	{
+	// called from ISR when timer completes
+	DChannelComm *pC=(DChannelComm*)aPtr;
+	pC->iTimerDfc.Add();
+	}
+
+void DChannelComm::TimerDfcFn(TAny* aPtr)
+	{
+	DChannelComm *pC=(DChannelComm*)aPtr;
+	pC->TimerDfc();
+	}
+
+void DChannelComm::TimerDfc()
+	{
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	if (iRxOutstanding)
+		{
+		if (iRxGetIndex==iRxPutIndex)
+			{
+			// buffer empty after timeout period, so complete
+			iRxBufCompleteIndex=iRxPutIndex;
+			iRxOutstanding=EFalse;
+			iRxOneOrMore=0;
+			__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+			DoCompleteRx();
+			return;
+			}
+		// buffer not empty, so drain buffer and requeue timer
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+		DoDrainRxBuffer(iRxPutIndex);
+		return;
+		}
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	}
+
+void DChannelComm::DrainRxDfc(TAny* aPtr)
+	{
+	DChannelComm *pC=(DChannelComm*)aPtr;
+	pC->DoDrainRxBuffer(pC->iRxPutIndex);
+	}
+
+// Drain RX buffer in a DFC
+void DChannelComm::DoDrainRxBuffer(TInt aEndIndex)
+	{
+	// if RX completion DFC is queued, leave buffer draining to it
+	if (iRxCompleteDfc.Queued())
+		return;
+
+	LOG(("DoDrainRxBuffer(aEndIndex=%d) iRxDesPos=%d iRxBufReq.iLen=%d", aEndIndex, iRxDesPos, iRxBufReq.iLen));
+    
+	// If there's an Rx request with bytes outstanding...
+	if (iRxBufReq.iBuf && iRxDesPos<iRxBufReq.iLen)
+        {
+        TInt space=iRxBufReq.iLen-iRxDesPos; // the amount of the client buffer left to fill
+        TInt avail=aEndIndex-iRxGetIndex;	 // the amount of data in the Rx buffer to copy to the client buffer
+        if (avail<0) // true if the data to drain wraps around the end of the buffer (i.e. the last byte to copy has a linear address less than that of the first byte)
+            avail+=iRxBufSize;
+        TInt len=Min(space,avail); // total number of bytes to drain
+
+		// Drain up to (but not beyond) the end of the Rx buffer
+        TInt len1=Min(len,iRxBufSize-iRxGetIndex);  // number of bytes to the end of the buffer
+        TPtrC8 des(iRxCharBuf+iRxGetIndex,len1);
+
+		TInt r = Kern::ThreadBufWrite(iClient, iRxBufReq.iBuf, des, iRxDesPos, KChunkShiftBy0, iClient);
+        if (r != KErrNone)
+            {
+            iRxError=r;
+            DoCompleteRx();
+            return;
+            }
+
+		// Update the client buffer offset and the Rx buffer read pointer with what we've done so far
+        TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+        iRxDesPos += len1;
+        iRxGetIndex+=len1;
+        if (iRxGetIndex>=iRxBufSize)
+            iRxGetIndex-=iRxBufSize;
+        __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+		// If the data wraps around the end of the Rx buffer, now write out the second part
+		// which starts at the beginning of the Rx buffer.
+        len-=len1;
+        if (len)
+            {
+            des.Set(iRxCharBuf,len);
+			r=Kern::ThreadBufWrite(iClient, iRxBufReq.iBuf, des, iRxDesPos, KChunkShiftBy0, iClient);
+            if (r != KErrNone)
+                {
+                iRxError=r;
+                DoCompleteRx();
+                return;
+                }
+
+			// Update client buffer offset and Rx buffer read offset
+            irq = __SPIN_LOCK_IRQSAVE(iLock);
+            iRxDesPos += len;
+            iRxGetIndex+=len;
+            __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+            }
+
+        // release flow control if necessary
+        if (iInputHeld && RxCount()<=iFlowControlLowerThreshold)
+            ReleaseFlowControl();
+
+        // if we are doing ReadOneOrMore, start the timer
+        if (iRxOneOrMore>0)
+            {
+            iTimer.OneShot(iTimeout);
+            }
+        }
+    }
+
+
+void DChannelComm::RxComplete()
+{
+	if (NKern::CurrentContext()==NKern::EInterrupt)
+		iRxCompleteDfc.Add();
+	else
+		DoCompleteRx();			
+}
+
+
+void DChannelComm::CompleteRxDfc(TAny* aPtr)
+	{
+	DChannelComm *pC=(DChannelComm*)aPtr;
+	pC->DoCompleteRx();
+	}
+
+void DChannelComm::DoCompleteRx()
+	{
+    LOG(("DoCompleteRx()"));
+	if (iRxOneOrMore>0)
+		iTimer.Cancel();
+	if (iRxBufReq.iLen)
+        {
+        iRxOneOrMore=0;
+        DoDrainRxBuffer(iRxBufCompleteIndex);
+		iRxBufReq.Complete(iClient, iRxError);
+		iRxDesPos=0;
+
+        iRxError=KErrNone;
+        // start Turnaround timer (got here because it received all data, timed out on a ReadOneOrMore or was terminated
+        // early by FailSignals)
+        RestartTurnaroundTimer();
+        }
+    else
+        {
+        Complete(ERx,KErrNone);
+        // do not start Turnaround (got here on a request Data Available Notification)
+        }
+    }
+
+
+void DChannelComm::TxComplete()
+{
+	if (NKern::CurrentContext()==NKern::EInterrupt)
+		iTxCompleteDfc.Add(); 
+	else
+		DoCompleteTx();			
+}
+
+
+void DChannelComm::FillTxDfc(TAny* aPtr)
+	{
+	DChannelComm *pC=(DChannelComm*)aPtr;
+	pC->DoFillTxBuffer();
+	}
+
+// Fill TX buffer in a DFC
+void DChannelComm::DoFillTxBuffer()
+	{
+    LOG(("DFTB %d =%d",iTxDesPos,iTxBufReq.iLen));
+	if (iTxBufReq.iBuf && iTxDesPos<iTxBufReq.iLen)
+        {
+        TInt space=iTxBufSize-TxCount()-1;
+        TInt remaining=iTxBufReq.iLen-iTxDesPos;
+        TInt len=Min(space,remaining);              // number of chars to transfer
+        TInt len1=Min(len,iTxBufSize-iTxPutIndex);  // number of chars to wrap point
+        TPtr8 des(iTxBuffer+iTxPutIndex,len1,len1);
+        LOG(("DFTxB sp = %d rem = %d iOPH = %d",space, remaining,iOutputHeld));
+		TInt r=Kern::ThreadBufRead(iClient, iTxBufReq.iBuf, des, iTxDesPos, KChunkShiftBy0);
+        if (r != KErrNone)
+            {
+            iTxError=r;
+            DoCompleteTx();
+            return;
+            }
+
+        TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+        iTxDesPos+=len1;
+        iTxPutIndex+=len1;
+        if (iTxPutIndex>=iTxBufSize)
+            iTxPutIndex-=iTxBufSize;
+        __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+        len-=len1;
+        if (len)
+            {
+            des.Set(iTxBuffer,len,len);
+			r=Kern::ThreadBufRead(iClient, iTxBufReq.iBuf, des, iTxDesPos, KChunkShiftBy0);
+            if (r != KErrNone)
+                {
+                iTxError=r;
+                DoCompleteTx();
+                return;
+                }
+
+            irq = __SPIN_LOCK_IRQSAVE(iLock);
+            iTxDesPos+=len;
+            iTxPutIndex+=len;
+            __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+            }
+        if (iTxDesPos==iTxBufReq.iLen)
+            {
+            // we have used up the client descriptor
+            if (iConfig.iHandshake & KConfigWriteBufferedComplete)
+                {
+                iTxOutstanding=EFalse;
+                DoCompleteTx();
+                }
+            }
+        // if TX buffer not empty and not flow controlled, make sure TX is enabled
+        if (iTxPutIndex!=iTxGetIndex  && (!iOutputHeld))
+            {
+            LOG(("Calling - DoTxBuff->ETx"));
+            EnableTransmit();
+            }
+        }
+    }
+
+void DChannelComm::CompleteTxDfc(TAny* aPtr)
+	{
+	DChannelComm *pC=(DChannelComm*)aPtr;
+	pC->DoCompleteTx();
+	}
+
+void DChannelComm::DoCompleteTx()
+	{
+	Complete(ETx,iTxError);
+	iTxError=KErrNone;
+	}
+
+void DChannelComm::Start()
+//
+// Start the driver receiving.
+//
+	{
+	LOG(("Start()"));
+	if (iStatus!=EClosed)
+		{
+		PddConfigure(iConfig);
+		PddStart();
+		iStatus=EActive;
+		if ((iConfig.iHandshake & KConfigSendXoff) && iJamChar>=0)
+			EnableTransmit(); // Send XOn if there is one
+		}
+	}
+
+void DChannelComm::BreakOn()
+//
+// Start the driver breaking.
+//
+	{
+	LOG(("BreakOn()"));
+	iFlags&=(~KBreakPending);
+	iFlags|=KBreaking;
+	PddBreak(ETrue);
+	iBreakTimer.OneShot(iBreakTimeMicroSeconds, DChannelComm::FinishBreak, this);
+	}
+
+void DChannelComm::BreakOff()
+//
+// Stop the driver breaking.
+//
+	{
+	LOG(("BreakOff()"));
+	PddBreak(EFalse);
+	iFlags&=(~(KBreakPending|KBreaking));
+	}
+
+void DChannelComm::AssertFlowControl()
+	{
+	iInputHeld=ETrue;
+	SetSignals(0,iFlowControlSignals);
+	if (iConfig.iHandshake&KConfigSendXoff)		// Doing input XON/XOFF
+		{
+		iJamChar=iConfig.iXoffChar;				// set up to send Xoff
+		EnableTransmit();						// Make sure we are transmitting
+		}
+	}
+
+void DChannelComm::ReleaseFlowControl()
+	{
+	iInputHeld=EFalse;
+	SetSignals(iFlowControlSignals,0);
+	if (iConfig.iHandshake&KConfigSendXoff)		// Doing input XON/XOFF
+		{
+		iJamChar=iConfig.iXonChar;				// set up to send Xon
+		EnableTransmit();						// Make sure we are transmitting
+		}
+	}
+
+TInt DChannelComm::SetRxBufferSize(TInt aSize)
+//
+// Set the receive buffer size.
+//
+	{
+	LOG(("SetRxBufferSize(aSize=0x%X)", aSize));
+	aSize=(aSize+3)&~3;
+	TUint8 *newBuf=(TUint8*)Kern::ReAlloc(iRxCharBuf,aSize<<1);
+	if (!newBuf)
+		return KErrNoMemory;
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	iRxCharBuf=newBuf;
+	iRxErrorBuf=newBuf+aSize;
+	iRxBufSize=aSize;
+	iFlowControlLowerThreshold=aSize>>2;
+	iFlowControlUpperThreshold=3*aSize>>2;
+	iRxDrainThreshold=aSize>>1;
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	ResetBuffers(EFalse);
+	return KErrNone;
+	}
+
+TInt DChannelComm::TurnaroundSet(TUint aNewTurnaroundMilliSeconds)
+	{
+	LOG(("TurnaroundSet(val=0x%X)", aNewTurnaroundMilliSeconds));
+	TInt r = KErrNone;
+	iTurnaroundMinMilliSeconds = aNewTurnaroundMilliSeconds;
+	return r;
+	}
+
+TBool DChannelComm::TurnaroundStopTimer()
+// Stop the timer and DFC
+	{
+	LOG(("TurnaroundStopTimer()"));
+	
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	TBool result = iTurnaroundTimerRunning;
+	if(result)
+		iTurnaroundTimerRunning = EFalse;	
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+	if (result)
+		{
+		iTurnaroundTimer.Cancel();
+		iTurnaroundDfc.Cancel();
+		}
+	return result;
+	}
+
+TInt DChannelComm::TurnaroundClear()
+// Clear any old timer and start timer based on new turnaround 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 if the requested 
+// turnaround time is elapsed else will only start after it is elapsed.
+	{
+	LOG(("TurnaroundClear()"));
+	TInt r = KErrNone;
+	TUint delta = 0;
+
+	if(iTurnaroundTimerStartTimeValid == 1)
+		{
+		//Calculate the turnaround time elapsed so far.
+		delta = (NKern::TickCount() - iTurnaroundTimerStartTime) * NKern::TickPeriod();
+		}
+    if(delta < iTurnaroundMicroSeconds)
+		{
+        iTurnaroundMinMilliSeconds = (iTurnaroundMicroSeconds - delta)/1000;
+        iTurnaroundTimerStartTimeValid = 3; //Just to make sure that the turnaround timer start time is not captured.
+        RestartTurnaroundTimer();
+		}
+    else
+		{
+		if(TurnaroundStopTimer())
+			{
+			// if a write is waiting, start a DFC to run it
+			TurnaroundStartDfcImplementation(EFalse);
+			}
+		}
+	iTurnaroundMinMilliSeconds = 0;
+	return r;
+	}
+
+TInt DChannelComm::RestartTurnaroundTimer()
+	{
+	LOG(("RestartTurnaroundTimer()"));
+	TInt r=KErrNone;
+
+	// POLICY: if timer is running from a previous read, stop it and re-start it
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	TBool cancelDfcs = (iTurnaroundMinMilliSeconds > 0) && iTurnaroundTimerRunning;
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	if (cancelDfcs) 
+		{
+		iTurnaroundTimer.Cancel();
+		iTurnaroundDfc.Cancel();
+		}
+
+	// Start the timer & update driver state to reflect that the timer is running
+	TInt timeout = 0;
+	irq = __SPIN_LOCK_IRQSAVE(iLock);
+	if(iTurnaroundMinMilliSeconds > 0)
+		{
+		iTurnaroundTimerRunning = ETrue;
+		timeout = NKern::TimerTicks(iTurnaroundMinMilliSeconds);
+		//Record the time stamp of turnaround timer start
+		if(iTurnaroundTimerStartTimeValid != 3)
+		    iTurnaroundTimerStartTime = NKern::TickCount();
+		iTurnaroundTimerStartTimeValid = 1;
+		}
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	if (timeout)
+		r=iTurnaroundTimer.OneShot(timeout);
+	return r;
+	}
+
+void DChannelComm::TurnaroundStartDfc(TAny* aSelf)
+	{
+	DChannelComm* self = (DChannelComm*)aSelf;
+	self->TurnaroundStartDfcImplementation(ETrue);		// in ISR so Irqs are already disabled
+	}
+
+void DChannelComm::TurnaroundStartDfcImplementation(TBool aInIsr)
+	{
+	LOG(("TurnaroundStartDfcImplementation(inIsr=%d)", aInIsr));
+	TInt irq=0;
+    if(!aInIsr)
+		irq = __SPIN_LOCK_IRQSAVE(iLock);
+	else 
+		__SPIN_LOCK(iLock);
+
+	iTurnaroundTimerRunning = EFalse;
+	if(iTurnaroundTransmitDelayed || iTurnaroundBreakDelayed)
+		{
+        if(aInIsr)
+			iTurnaroundDfc.Add();
+		else
+			{
+			if(!aInIsr)
+				__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+			else 
+				__SPIN_UNLOCK(iLock);
+			iTurnaroundDfc.Enque();
+			return;
+			}
+		}
+    if(!aInIsr)
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	else 
+		__SPIN_UNLOCK(iLock);
+	}
+
+void DChannelComm::TurnaroundTimeout(TAny* aSelf)
+	{
+	DChannelComm* self = (DChannelComm*)aSelf;
+	self->TurnaroundTimeoutImplementation();
+	}
+
+void DChannelComm::TurnaroundTimeoutImplementation()
+	{
+	LOG(("TurnaroundTimeoutImplementation()"));
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	
+	if(iTurnaroundBreakDelayed)
+		{
+		iTurnaroundBreakDelayed=EFalse;
+		if (iStatus==EClosed)
+			{
+            __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+			Complete(EBreak, KErrNotReady);
+			return;
+			}
+		else if(IsLineFail(iFailSignals))	// have signals changed in the meantime?
+			{
+            __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+			Complete(EBreak, KErrCommsLineFail);	// protected -> changed in signals ISR
+			return;
+			}
+		if (iTurnaroundTransmitDelayed)
+			{
+			//delay write by break instead of turnaround
+			iBreakDelayedTx = ETrue;
+			iTurnaroundTransmitDelayed=EFalse;
+			}
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+        BreakOn();
+		}
+	else if(iTurnaroundTransmitDelayed)
+		{
+		iTurnaroundTransmitDelayed = EFalse;		// protected -> prevent reentrant ISR
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+		
+		RestartDelayedTransmission();
+		}
+	else 
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	}
+
+void DChannelComm::ResetBuffers(TBool aResetTx)
+//
+// Reset the receive and maybe the transmit buffer.
+//
+	{
+	LOG(("ResetBuffers(aResetTx=%d)", aResetTx));
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	iRxPutIndex=0;
+	iRxGetIndex=0;
+	iRxBufCompleteIndex=0;
+	if (aResetTx)
+		{
+		iTxPutIndex=0;
+		iTxGetIndex=0;
+		}
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+	if (iStatus==EActive)
+		ReleaseFlowControl();
+	iInputHeld=EFalse;
+	}
+
+TInt DChannelComm::TransmitIsr()
+//
+// Return the next character to be transmitted to the ISR
+//
+	{
+	TInt tChar=iJamChar;			// Look for control character to jam in
+    if (tChar>=0)					// Control character to send
+        {
+		iJamChar=KTxNoChar;
+		}
+    else if (!iOutputHeld && iTxGetIndex!=iTxPutIndex)
+        {
+		// Get spinlock, disable interrupts to ensure we can reach the unlock 
+		// statement. An FIQ before unlock that attempted to get lock would 
+		// lead to CPU deadlock
+		TInt irqstate = __SPIN_LOCK_IRQSAVE(iLock);
+		
+		// output not held and buffer not empty, get next char
+		tChar=iTxBuffer[iTxGetIndex++];
+		if (iTxGetIndex==iTxBufSize)
+			iTxGetIndex=0;
+			
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irqstate);
+		}
+
+	return tChar;
+	}
+
+void DChannelComm::ReceiveIsr(TUint* aChar, TInt aCount, TInt aXonXoff)
+//
+// Handle received character block from the ISR.
+// aChar points to received characters, aCount=number received,
+// aXonXoff=1 if XON received, -1 if XOFF received, 0 if neither
+//
+	{
+	if (aXonXoff>0)
+		{
+		iOutputHeld &= ~KXoffSignal;	// Mark output ok. for XON/XOFF
+		if (iOutputHeld==0)
+			EnableTransmit();
+		}
+	else if (aXonXoff<0)
+		{
+		iOutputHeld |= KXoffSignal;		// Mark output held for XON/XOFF
+		}
+	if (aCount==0)						// if only XON or XOFF received
+		return;
+
+	// Get spinlock, disable interrupts to ensure we can reach the unlock 
+	// statement. An FIQ before unlock that attempted to get lock would 
+	// lead to CPU deadlock
+	TInt irqstate = __SPIN_LOCK_IRQSAVE(iLock);
+
+	TInt count = RxCount();
+	iReceived++;
+
+	// At or above the high water mark send xoff every other character
+    if (count>=iFlowControlUpperThreshold && ((count&1)!=0 || aCount>1))
+		AssertFlowControl();
+
+	TUint* pE=aChar+aCount;
+	TInt e=KErrNone;
+	TInt i=iRxPutIndex;
+	TInt g=iRxGetIndex;
+	TInt s=iRxBufSize;
+	g=g?g-1:s-1;
+	TInt p=iRxOutstanding?-1:0;
+    TInt thresh=iRxBufReq.iLen-iRxDesPos;
+	while(aChar<pE)
+		{
+		TUint c=*aChar++;
+
+		// Check for parity errors and replace char if so configured.
+		if (c & KReceiveIsrParityError)
+			{
+			// Replace bad character
+			if (iConfig.iParityError==KConfigParityErrorReplaceChar)
+				c = c & ~(0xff|KReceiveIsrParityError) | iConfig.iParityErrorChar;
+			// Ignore parity error
+			if (iConfig.iParityError==KConfigParityErrorIgnore)
+				c = c & ~KReceiveIsrParityError;
+			}
+		
+		if (i!=g)
+			{
+			iRxCharBuf[i]=(TUint8)c;
+			iRxErrorBuf[i]=(TUint8)(c>>24);
+
+			if (c & KReceiveIsrMaskError)
+				{
+				__UART_RX_ERROR(c);
+				if (c & KReceiveIsrOverrunError)
+					e = KErrCommsOverrun;
+				else if (c & KReceiveIsrBreakError)
+					e = KErrCommsBreak;
+				else if (c & KReceiveIsrFrameError)
+					e = KErrCommsFrame;
+				else if (c & KReceiveIsrParityError)
+					e = KErrCommsParity;
+				}
+			count++;
+			if (++i==s)
+				i=0;
+			if (p<0)
+				{
+				if (e || IsTerminator(TUint8(c)) || count==thresh)
+					{
+					// need to complete client request
+					iRxError = e;
+					p=i;
+					}
+				}
+			}
+		else
+			{
+			__OVERRUN();
+			// buffer overrun, discard character
+			e=KErrCommsOverrun;
+
+			// make sure client is informed of overrun error
+			iRxError=e;
+
+			// discard remaining characters and complete
+			p=i;
+			break;
+			}
+		}
+	iRxPutIndex=i;
+
+	if (iRxOutstanding)
+		{
+		if (p>=0)
+			{
+			// need to complete client request
+			iRxBufCompleteIndex=p;
+			iRxOutstanding=EFalse;
+            RxComplete();
+			}
+		else if (count>=iRxDrainThreshold)
+			{
+			// drain buffer but don't complete
+			DrainRxBuffer();
+			}
+		else if (iRxOneOrMore<0)
+			{
+			// doing read one or more - drain the buffer
+			// this will start the timer
+			iRxOneOrMore=1;
+			DrainRxBuffer();
+			}
+		}
+
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irqstate);
+
+	if (iNotifyData)
+		{
+		iNotifyData=EFalse;
+        RxComplete();
+		}
+	}
+
+void DChannelComm::CheckTxBuffer()
+	{
+	// if buffer count < threshold, fill from client buffer
+	TInt count=TxCount();
+    if (iTxOutstanding && iTxDesPos<iTxBufReq.iLen && count<iTxFillThreshold)
+		iTxFillDfc.Add();
+	else if (count==0)
+		{
+		// TX buffer is now empty - see if we need to complete anything
+		if (iTxOutstanding)
+			{
+            if (iTxBufReq.iLen==0)
+				{
+				// request was a zero-length write - complete if hardware flow control
+				// is not asserted
+				if ((~iSignals & iHoldSignals)==0)
+					{
+					iTxOutstanding=EFalse;
+                    TxComplete();
+					}
+				}
+			else
+				{
+				// request was normal TX - complete now if not doing early completion
+				if (!(iConfig.iHandshake&KConfigWriteBufferedComplete))
+					{
+					iTxOutstanding=EFalse;
+					TxComplete();
+					}
+				}
+			}
+		}
+	}
+
+
+//
+// Pdd callback
+//
+void DChannelComm::UpdateSignals(TUint aSignals)
+	{
+    __KTRACE_OPT(KHARDWARE,Kern::Printf("CommSig: Upd %08x",aSignals));
+    iSignals=(iSignals&~KDTEInputSignals)|(aSignals&KDTEInputSignals);
+    DoSigNotify();	
+	}
+
+
+
+/**
+ Handle a state change from the PDD. Called in ISR or DFC context.
+ */
+void DChannelComm::StateIsr(TUint aSignals)
+    {
+    iSignals=(iSignals&~KDTEInputSignals)|(aSignals&KDTEInputSignals);
+    if (iSignalsReq->IsReady() && ((iSignals^iNotifiedSignals)&iSigNotifyMask) )
+        {
+        iSigNotifyDfc.Add();
+        }
+    if (IsLineFail(iFailSignals))
+        {
+        if (iRxOutstanding)
+            {
+            iRxError=KErrCommsLineFail;
+            iRxBufCompleteIndex=iRxPutIndex;
+            iRxOutstanding=EFalse;
+			RxComplete();				
+            }
+        if (iTxOutstanding)
+            {
+            iTxError = KErrCommsLineFail;
+            iTxOutstanding=EFalse;
+			TxComplete();
+			}
+        }
+
+	//
+	// Now we must determine if output is to be held
+	//
+    TUint status = ~iSignals & iHoldSignals;
+    if (iOutputHeld & KXoffSignal)
+        status |= KXoffSignal;      // Leave the xon/xoff handshake bit
+
+    LOG(("State - ISR - 0x%x",status));
+    iOutputHeld=status;             // record new flow control state
+    if (iTxGetIndex==iTxPutIndex)
+        {
+        // Tx buffer is empty
+        if (iTxOutstanding && iTxBufReq.iLen==0 && (status&~KXoffSignal)==0)
+            {
+            // if hardware flow control released, complete zero-length write
+            iTxOutstanding=EFalse;
+			TxComplete();
+			}
+        }
+    else if (status==0)
+        {
+        // Tx buffer not empty and flow control released, so restart transmission
+        LOG(("Calling LDD:EnTx"));
+        EnableTransmit();
+        }
+    }
+
+// check if transmitter is flow controlled
+void DChannelComm::CheckOutputHeld()
+	{
+	iOutputHeld=(iOutputHeld & KXoffSignal) | (~iSignals & iHoldSignals);
+    LOG(("CheckOPH IOH = %d",iOutputHeld));
+	}
+
+void DChannelComm::HandleMsg(TMessageBase* aMsg)
+	{
+
+	if (iStandby)
+		{ // postpone message handling to transition from standby
+		iMsgHeld=ETrue;
+		return;
+		}
+
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+	LOG(("HandleMsg(%x a1=%x, a2=%x)", m.iValue, m.Int1(), m.Int2()));
+	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
+        DoRequest(~id,m.Ptr1(),m.Ptr2());
+		m.Complete(KErrNone,ETrue);
+		}
+	else
+		{
+		// DoControl
+		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+		m.Complete(r,ETrue);
+		}
+	}
+
+void DChannelComm::DoCancel(TInt aMask)
+//
+// Cancel an outstanding request.
+//
+	{
+	LOG(("DoCancel(%d)", aMask));
+	if (aMask & RBusDevComm::ERequestReadCancel)
+		{
+		TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+		iRxOutstanding=EFalse;
+		iNotifyData=EFalse;
+		iRxDesPos=0;
+        iRxBufReq.iLen=0;
+		iRxError=KErrNone;
+		iRxOneOrMore=0;
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+		iRxCompleteDfc.Cancel();
+		iRxDrainDfc.Cancel();
+		iTimer.Cancel();
+		iTimerDfc.Cancel();
+		Complete(ERx,KErrCancel);
+		}
+	if (aMask & RBusDevComm::ERequestWriteCancel)
+		{
+		TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+        iTurnaroundTransmitDelayed = EFalse;
+        iTxPutIndex=0;
+        iTxGetIndex=0;
+        iTxOutstanding=EFalse;
+        iTxDesPos=0;
+        iTxBufReq.iLen=0;
+		iTxError=KErrNone;
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+		iTxCompleteDfc.Cancel();
+		iTxFillDfc.Cancel();
+		Complete(ETx,KErrCancel);
+		}
+    if (aMask & RBusDevComm::ERequestNotifySignalChangeCancel)
+        {
+        iSigNotifyDfc.Cancel();
+        Complete(ESigChg,KErrCancel);
+        }
+    if (aMask & RBusDevComm::ERequestBreakCancel)
+		{
+	 	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+		if (iTurnaroundBreakDelayed)
+			iTurnaroundBreakDelayed=EFalse;
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+		iBreakDfc.Cancel();
+		iBreakTimer.Cancel();
+		FinishBreakImplementation(KErrCancel);
+		}
+	}
+
+/**
+ Intercept messages in client context before they are sent to the DFC queue
+ */
+TInt DChannelComm::SendMsg(TMessageBase* aMsg)
+	{
+	TInt r = KErrNone;
+	TInt max;
+	TInt len = 0;
+	TThreadMessage* m = (TThreadMessage*)aMsg;
+
+	// Handle ECloseMsg & Cancel
+    TInt id=aMsg->iValue;
+    if (id==(TInt)ECloseMsg || id==KMaxTInt)
+        {
+		LOG(("SendMsg(%s)", (id==KMaxTInt)?"Cancel":"ECloseMsg"));
+		// do nothing cos these are handled on the DFC side
+        }
+	
+	// Handle control messages that access user memory here in client context
+    else if (id >= 0) 
+		{
+		TAny* a1 = m->iArg[0];
+		switch (aMsg->iValue) 
+			{
+			case RBusDevComm::EControlConfig:
+				{			
+				LOG(("SendMsg(EControlConfig, %x)", a1));
+				TPtrC8 cfg((const TUint8*)&iConfig,sizeof(iConfig));
+				return Kern::ThreadDesWrite(iClient,a1,cfg,0,KTruncateToMaxLength,iClient);
+				}
+			case RBusDevComm::EControlSetConfig:
+				{
+				LOG(("SendMsg(EControlSetConfig, %x)", a1));
+				if (AreAnyPending()) 
+					; // r = ESetConfigWhileRequestPending;
+				else
+					r = Kern::PinVirtualMemory(iPinObjSetConfig, (TLinAddr)a1, sizeof(TCommConfigV01));
+				}
+				break;
+			case RBusDevComm::EControlCaps:
+				{
+				LOG(("SendMsg(EControlCaps, %x)", a1));
+				TCommCaps2 caps;
+				PddCaps(caps);
+				return Kern::ThreadDesWrite(iClient,a1,caps,0,KTruncateToMaxLength,iClient);
+				}
+			default:
+				// Allow other control messages to go to DFC thread
+				LOG(("SendMsg(Ctrl %d, %x)", aMsg->iValue, a1));
+				break;
+			}
+		}
+
+
+	// Handle requests
+	else 
+		{
+		TRequestStatus* status = (TRequestStatus*)m->iArg[0];
+		TAny* a1 = m->iArg[1];
+		TAny* a2 = m->iArg[2];
+		TInt reqNo = ~aMsg->iValue;
+		TInt irq;
+		switch (reqNo)
+			{
+			case RBusDevComm::ERequestRead:
+				{
+			    iNotifyData=EFalse;
+				// If client has *not* provided a buffer pointer, it means they only want
+				// to know when data becomes available.
+				if (!a1)
+					{
+					irq = __SPIN_LOCK_IRQSAVE(iLock);
+					TBool isEmpty = (iRxPutIndex==iRxGetIndex);
+					iNotifyData = isEmpty;
+					__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+					if (!isEmpty) // if Rx buffer has bytes in it we can complete the request immediately
+						{
+						Kern::RequestComplete(status, KErrNone);
+						return KErrNone;
+						}
+					// Do not start the Turnaround timer as this is not a Read request but a request for Data Available notification
+					LOG(("--Buf Empty--"));
+					}
+
+				// Get buffer length if one has been given
+				if (a2)
+					r = Kern::ThreadRawRead(iClient,a2,&len,sizeof(len)); 
+
+				// Check the client descriptor is valid and large enough to hold the required amount of data.
+				if (a1 && r==KErrNone) 
+					{
+					max = Kern::ThreadGetDesMaxLength(iClient, a1);
+					if (max<Abs(len) || max<0)
+						r = KErrGeneral; // do not start the Turnaround timer (invalid Descriptor this read never starts)
+					}
+
+				LOG(("SendMsg(ERequestRead, %x, len=%d) max=%d r=%d", a1, len, max, r));
+
+				// Set client descriptor length to zero & set up client buffer object
+				if (a1 && r==KErrNone) 
+					{
+					TPtrC8 p(NULL,0);
+					r = Kern::ThreadDesWrite(iClient,a1,p,0,0,iClient);
+					if (r == KErrNone)
+						r = iRxBufReq.Setup(status, a1, len);
+					}
+				}
+			break;
+
+
+			//
+			// ERequestWrite
+			//
+			case RBusDevComm::ERequestWrite:
+				if (iStatus==EClosed)
+					r = KErrNotReady;
+				else if (!a1) 
+					r = KErrArgument;
+				else 
+					r=Kern::ThreadRawRead(iClient, a2, &len, sizeof(len));
+				LOG(("SendMsg(ERequestWrite, %x, len=%d) r=%d", a1, len, r));
+
+				// Setup pending client request for this write
+				if (r==KErrNone)
+					r = iTxBufReq.Setup(status, a1, len);		
+				break;
+
+
+			//
+			// ERequestBreak: a1 points to the number of microseconds to break for
+			//
+			case RBusDevComm::ERequestBreak:
+				r = Kern::ThreadRawRead(iClient, a1, &iBreakTimeMicroSeconds, sizeof(TInt));
+				if (r == KErrNone)
+					r = iBreakStatus->SetStatus(status);					
+				LOG(("SendMsg(ERequestBreak, %x) bktime=%d r=%d", a1, iBreakTimeMicroSeconds, r));
+				break;
+
+
+			//
+			// ERequestNotifySignalChange:	a1 points to user-side int to receive the signals bitmask
+			//								a2 points to the bitmask of signals the user is interested in
+			//
+			case RBusDevComm::ERequestNotifySignalChange:
+				LOG(("SendMsg(ERequestNotifySignalChange, %x, %x)", a1, a2));
+				if (!a1 || !a2)
+					{
+					r = KErrArgument;
+					break;
+					}
+				// Setup word-sized client buffer
+				r = Kern::ThreadRawRead(iClient,a2,&iSigNotifyMask,sizeof(TUint));
+				irq = __SPIN_LOCK_IRQSAVE(iLock);
+				if (r==KErrNone) 
+					{
+					r = iSignalsReq->SetStatus(status);
+					if (r==KErrNone) 
+						iSignalsReq->SetDestPtr(a1);
+					}
+				LOG(("ERequestNotifySignalChange: mask is %x, r is %d", iSigNotifyMask, r));
+				__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+				break;
+
+
+			// Unknown request
+			default:
+				LOG(("SendMsg(req %d, %x, %x)", reqNo, a1, a2));
+				r = KErrNotSupported;
+				break;
+
+			}
+
+			// If the request has an error, complete immediately
+			if (r!=KErrNone)
+				Kern::RequestComplete(status, r);
+		}
+
+	// Send the client request to the DFC queue unless there's been an error
+	if (r==KErrNone)
+		r = DLogicalChannel::SendMsg(aMsg);
+	LOG(("<SendMsg ret %d", r));
+	return r;
+
+	}
+
+
+/**
+ Handle asynchronous requests. Called in DFC context.
+ */
+void DChannelComm::DoRequest(TInt aReqNo, TAny* a1, TAny* a2)
+    {
+	LOG(("DoRequest(%d %x %x)", aReqNo, a1, a2));
+
+    //
+    // First check if we have started
+    //
+    if (iStatus==EOpen)
+        {
+        Start();
+        CheckOutputHeld();
+        SetSignals(iAutoSignals,0);
+        LOG(("DReq- RFC"));
+        ReleaseFlowControl();
+        }
+    //
+    // Check for a line fail
+    //
+    if (IsLineFail(iFailSignals))
+		{
+		Complete(EAll, KErrCommsLineFail);
+		return;
+		}	
+
+    //
+    // Now we can dispatch the async request
+    //
+    switch (aReqNo)
+        {
+        case RBusDevComm::ERequestRead:
+			InitiateRead(iRxBufReq.iLen);
+            break;
+
+        case RBusDevComm::ERequestWrite:
+            {
+			
+			// See if we need to delay the write
+            TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+			iTurnaroundTransmitDelayed = iTurnaroundTimerRunning!=0;
+			iBreakDelayedTx = (iFlags & KBreaking);
+			__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+			// If we do need to delay the write
+            if (iTurnaroundTransmitDelayed || iBreakDelayedTx)
+                break;
+			
+			//
+			InitiateWrite();
+            break;
+            }
+
+        case RBusDevComm::ERequestNotifySignalChange:
+            iNotifiedSignals = iSignals;
+			DoSigNotify();
+            break;
+            
+        case RBusDevComm::ERequestBreak:
+			if(iTurnaroundTimerRunning)
+				iTurnaroundBreakDelayed = ETrue;
+			else
+				BreakOn();
+			break;
+
+        }
+    }
+
+/**
+ Called in DFC context upon receipt of ERequestRead
+ */
+void DChannelComm::InitiateRead(TInt aLength)
+    {
+    LOG(("InitiateRead(%d)", aLength));
+    iRxOutstanding=EFalse;
+	iRxOneOrMore=0;
+
+    // Complete zero-length read immediately
+    if (aLength==0)
+        {
+		iRxBufReq.Complete(iClient, KErrNone);
+        RestartTurnaroundTimer();
+        return;
+        }
+
+	TBool length_negative = (aLength<0);
+	if (length_negative)
+		aLength = -aLength;
+	iRxBufReq.iLen=aLength;
+
+    // If the RX buffer is empty, we must wait for more data
+    TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+    if (iRxPutIndex==iRxGetIndex)
+        {
+		if (length_negative)
+            iRxOneOrMore=-1;        // -1 because timer not started
+        iRxOutstanding=ETrue;
+        __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+        return;
+        }
+    __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+    // RX buffer contains characters, must scan buffer and then complete
+	if (length_negative)
+        {
+        // ReceiveOneOrMore, up to -aLength characters
+        iRxOneOrMore=1;
+        }
+    TInt getIndex=iRxGetIndex;
+    TInt count=0;
+    TUint stat=0;
+	TBool complete=EFalse;
+    while(!complete)
+        {
+        while(count<aLength && getIndex!=iRxPutIndex)
+            {
+            if ((stat=iRxErrorBuf[getIndex])!=0 || IsTerminator(iRxCharBuf[getIndex]))
+                {
+                // this character will complete the request
+                if (++getIndex==iRxBufSize)
+                    getIndex=0;
+                count++;
+                complete=ETrue;
+                break;
+                }
+            if (++getIndex==iRxBufSize)
+                getIndex=0;
+            count++;
+            }
+        if (count==aLength)
+            complete=ETrue;
+        if (!complete)
+            {
+            TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+            if (getIndex==iRxPutIndex)
+                {
+                // not enough chars to complete request, so set up to wait for more
+                iRxOutstanding=ETrue;
+                __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+                if (count)
+                    DoDrainRxBuffer(getIndex);
+                return;
+                }
+            // more characters have arrived, loop again
+            __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+            }
+        }
+
+    // can complete request right now
+    TInt e=KErrNone;
+    if (stat)
+        {
+        stat<<=24;
+        if (stat & KReceiveIsrOverrunError)
+            e = KErrCommsOverrun;
+        else if (stat & KReceiveIsrBreakError)
+	        e = KErrCommsBreak;
+        else if (stat & KReceiveIsrFrameError)
+            e = KErrCommsFrame;
+        else if (stat & KReceiveIsrParityError)
+            e = KErrCommsParity;
+        }
+    if (iRxError==KErrNone)
+        iRxError=e;
+    iRxBufCompleteIndex=getIndex;
+    DoCompleteRx();
+    }
+
+/**
+ Called in DFC context to start a write or a delayed write
+ */
+void DChannelComm::InitiateWrite()
+    {
+    LOG(("InitiateWrite() len=%d", iTxBufReq.iLen));
+
+
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	iTxDesPos=0;
+	iTurnaroundTimerStartTime = 0;
+	iTurnaroundTimerStartTimeValid = 2;
+	if (~iSignals & iFailSignals)
+		{
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+		iTxBufReq.Complete(iClient, KErrCommsLineFail);
+		return;
+		}
+	if (iTxBufReq.iLen==0)
+		{
+		if (iTxPutIndex==iTxGetIndex && (~iSignals & iHoldSignals)==0)
+			{
+			__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+			iTxBufReq.Complete(iClient, KErrNone);
+			return;
+			}
+		}
+
+	iTxOutstanding=ETrue;
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	if (iTxBufReq.iLen!=0)
+		DoFillTxBuffer();
+	}
+
+void DChannelComm::SigNotifyDfc(TAny* aPtr)
+	{
+	((DChannelComm*)aPtr)->DoSigNotify();
+	}
+
+void DChannelComm::DoSigNotify()
+    {
+	// Atomically update iNotifiedSignals and prepare to signal
+	TBool do_notify = EFalse;
+    TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+    TUint orig_sig=iNotifiedSignals;
+    if (iSignalsReq->IsReady() && ( iNotifiedSignals==0xffffffff || ((iSignals^iNotifiedSignals)&iSigNotifyMask) ) )
+        {
+        iNotifiedSignals=iSignals;
+        do_notify=ETrue;
+        }
+    __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+    __KTRACE_OPT(KHARDWARE,Kern::Printf("CommSig: Orig=%08x New %08x Mask %08x",orig_sig,iNotifiedSignals,iSigNotifyMask));
+    if (do_notify)
+        {
+        TUint changed=iSigNotifyMask;
+        if (orig_sig!=0xffffffff)
+            changed&=(orig_sig^iNotifiedSignals);
+        changed=(changed<<12)|(iNotifiedSignals&iSigNotifyMask);
+
+		// Write the result back to client memory and complete the request
+		__KTRACE_OPT(KHARDWARE,Kern::Printf("CommSig: Notify %08x",changed));
+		LOG(("DoSigNotify: %08x",changed));
+		TUint& rr = iSignalsReq->Data();
+		rr = changed;
+		Kern::QueueRequestComplete(iClient, iSignalsReq, KErrNone);
+		}
+    }
+
+
+/**
+ Manually read and act on signals
+ */
+void DChannelComm::UpdateAndProcessSignals()
+    {
+    TUint signals=Signals();
+    TBool notify=EFalse;
+    TBool complete_rx=EFalse;
+    TBool complete_tx=EFalse;
+    TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+    iSignals=(iSignals&~KDTEInputSignals)|(signals&KDTEInputSignals);
+    if (iSignalsReq->IsReady() && ((iSignals^iNotifiedSignals)&iSigNotifyMask) )
+        {
+        notify=ETrue;
+        }
+    if (IsLineFail(iFailSignals))
+        {
+        if (iRxOutstanding)
+            {
+            iRxError=KErrCommsLineFail;
+            iRxBufCompleteIndex=iRxPutIndex;
+            iRxOutstanding=EFalse;
+            complete_rx=ETrue;
+            }
+        if (iTxOutstanding)
+            {
+            iTxError = KErrCommsLineFail;
+            iTxOutstanding=EFalse;
+            complete_tx=ETrue;
+            }
+        }
+    //
+    // Now we must determine if output is to be held
+    //
+    TUint status = ~iSignals & iHoldSignals;
+    if (iOutputHeld & KXoffSignal)
+        status |= KXoffSignal;      // Leave the xon/xoff handshake bit
+
+    iOutputHeld=status;             // record new flow control state
+    if (iTxGetIndex==iTxPutIndex)
+        {
+        // Tx buffer is empty
+        if (iTxOutstanding && iTxBufReq.iLen==0 && (status&~KXoffSignal)==0)
+            {
+            // if hardware flow control released, complete zero-length write
+            iTxOutstanding=EFalse;
+            complete_tx=ETrue;
+            }
+        }
+    else if (status==0)
+        {
+        // Tx buffer not empty and flow control released, so restart transmission
+        EnableTransmit();
+        }
+    __SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+    if (notify)
+        DoSigNotify();
+    if (complete_rx)
+        DoCompleteRx();
+    if (complete_tx)
+        DoCompleteTx();
+    }
+
+
+TUint DChannelComm::FailSignals(TUint aHandshake)
+	{
+	TUint r=0;
+	if ((aHandshake&(KConfigObeyCTS|KConfigFailCTS))==(KConfigObeyCTS|KConfigFailCTS))
+		r|=KSignalCTS;
+	if ((aHandshake&(KConfigObeyDSR|KConfigFailDSR))==(KConfigObeyDSR|KConfigFailDSR))
+		r|=KSignalDSR;
+	if ((aHandshake&(KConfigObeyDCD|KConfigFailDCD))==(KConfigObeyDCD|KConfigFailDCD))
+		r|=KSignalDCD;
+	return r;
+	}
+
+TUint DChannelComm::HoldSignals(TUint aHandshake)
+	{
+	TUint r=0;
+	if (aHandshake & KConfigObeyCTS)
+		r|=KSignalCTS;
+	if (aHandshake & KConfigObeyDSR)
+		r|=KSignalDSR;
+	if (aHandshake & KConfigObeyDCD)
+		r|=KSignalDCD;
+	return r;
+	}
+
+TUint DChannelComm::FlowControlSignals(TUint aHandshake)
+	{
+	TUint r=0;
+	if (!(aHandshake & KConfigFreeRTS))
+		r|=KSignalRTS;
+	else if (!(aHandshake & KConfigFreeDTR))
+		r|=KSignalDTR;
+	return r;
+	}
+
+TUint DChannelComm::AutoSignals(TUint aHandshake)
+	{
+	TUint r=0;
+	if (!(aHandshake & KConfigFreeRTS) && !(aHandshake & KConfigFreeDTR))
+		r|=KSignalDTR;
+	return r;
+	}
+
+TInt DChannelComm::SetConfig(TCommConfigV01& c)
+	{
+	LOG(("SetConfig(...)"));
+	TBool restart = EFalse;
+	TBool purge = EFalse;
+	TBool changeTerminators=EFalse;
+	TInt irq;
+	TInt r;
+
+	if(c.iTerminatorCount>KConfigMaxTerminators)
+		return KErrNotSupported;
+	if ((r=ValidateConfig(c))!=KErrNone)
+		return r;
+	TUint failSignals=FailSignals(c.iHandshake);
+	if (IsLineFail(failSignals))
+		return KErrCommsLineFail;
+	if (iConfig.iRate != c.iRate
+		|| iConfig.iDataBits != c.iDataBits
+		|| iConfig.iStopBits != c.iStopBits
+		|| iConfig.iParity != c.iParity
+		|| iConfig.iFifo != c.iFifo
+		|| iConfig.iSpecialRate != c.iSpecialRate
+		|| iConfig.iSIREnable != c.iSIREnable
+		|| iConfig.iSIRSettings != c.iSIRSettings)
+		{
+		restart = ETrue;
+		}
+	else if (iConfig.iParityErrorChar != c.iParityErrorChar
+		|| iConfig.iParityError != c.iParityError
+		|| iConfig.iXonChar != c.iXonChar
+		|| iConfig.iXoffChar != c.iXoffChar
+		|| (iConfig.iHandshake&(KConfigObeyXoff|KConfigSendXoff))
+			!= (c.iHandshake&(KConfigObeyXoff|KConfigSendXoff)))
+		{
+		purge = ETrue;
+		}
+	else
+		{
+		if (iConfig.iTerminatorCount==c.iTerminatorCount)
+			{
+			for (TInt i=0; i<iConfig.iTerminatorCount; i++)
+				{
+				if (iConfig.iTerminator[i]!=c.iTerminator[i])
+					{
+					changeTerminators=ETrue;
+					break;
+					}
+				}
+			}
+		else
+			changeTerminators=ETrue;
+		if (!changeTerminators && c.iHandshake == iConfig.iHandshake)
+			return r;	// nothing to do.
+		}
+	if (iStatus==EActive && (restart || purge))
+		{
+		SetSignals(0,iFlowControlSignals|iAutoSignals); // Drop RTS
+		Stop(EStopNormal);
+		iStatus=EOpen;
+		if(purge)
+			ResetBuffers(ETrue);
+		iConfig=c;
+		iFailSignals=failSignals;
+		iHoldSignals=HoldSignals(c.iHandshake);
+		iFlowControlSignals=FlowControlSignals(c.iHandshake);
+		iAutoSignals=AutoSignals(c.iHandshake);
+		Start();
+		CheckOutputHeld();
+		SetSignals(iFlowControlSignals|iAutoSignals,0); // Assert RTS
+		irq = __SPIN_LOCK_IRQSAVE(iLock);
+		}
+	else
+		{
+		irq = __SPIN_LOCK_IRQSAVE(iLock);
+		if(purge)
+			ResetBuffers(ETrue);
+		iConfig=c;
+		iFailSignals=failSignals;
+		iHoldSignals=HoldSignals(c.iHandshake);
+		iFlowControlSignals=FlowControlSignals(c.iHandshake);
+		iAutoSignals=AutoSignals(c.iHandshake);
+		}
+	if (iConfig.iHandshake&KConfigObeyXoff)
+		{
+		iRxXonChar=c.iXonChar;
+		iRxXoffChar=c.iXoffChar;
+		}
+	else
+		{
+		iRxXonChar=0xffffffff;
+		iRxXoffChar=0xffffffff;
+		iOutputHeld&=~KXoffSignal;
+		}
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	if (iStatus==EActive)
+		ReleaseFlowControl();
+
+	// no request pending here, so no need to protect this against interrupts
+	if (restart || purge || changeTerminators)
+		{
+		memclr(iTerminatorMask, 32);
+		TInt i;
+		for (i=0; i<iConfig.iTerminatorCount; i++)
+			{
+			SetTerminator(iConfig.iTerminator[i]);
+			}
+		}
+	return r;
+	}
+
+TInt DChannelComm::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+//
+// Sync requests.
+//
+	{
+	LOG(("DoControl(aFunction=%d, a1=%x, a2=%x)", aFunction, a1, a2));
+
+	TInt r=KErrNone;
+
+	switch (aFunction)
+		{
+		case RBusDevComm::EControlSetConfig:
+			{
+			TCommConfigV01 c;
+			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);
+			}
+			Kern::UnpinVirtualMemory(iPinObjSetConfig);
+			break;
+
+		case RBusDevComm::EControlSignals:
+			{
+			UpdateAndProcessSignals();
+			r=iSignals;
+			break;
+			}
+		case RBusDevComm::EControlSetSignals:
+			{
+			TUint set=(TUint)a1;
+			TUint clear=(TUint)a2;
+			if (set & clear)
+;//				Kern::PanicCurrentThread(_L("D32COMM"), ESetSignalsSetAndClear);
+			else
+				{
+				if (iStatus==EOpen)
+					{
+					Start();
+					if (!(iConfig.iHandshake & KConfigFreeDTR) && !(clear & KSignalDTR))
+						set|=KSignalDTR; // Assert DTR
+					if (!(iConfig.iHandshake & KConfigFreeRTS) && !(clear & KSignalRTS))
+						set|=KSignalRTS; // Assert RTS
+					if (iConfig.iHandshake & KConfigSendXoff)
+						iJamChar=iConfig.iXonChar;
+					iInputHeld = EFalse;
+					CheckOutputHeld();
+					}
+				__e32_atomic_axo_ord32(&iSignals, ~(clear|set), set);
+				SetSignals(set,clear);
+				}
+			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=iRxBufSize;
+			break;
+
+		case RBusDevComm::EControlSetReceiveBufferLength:
+			if (AreAnyPending())
+;//				iThread->Panic(_L("D32COMM"),ESetReceiveBufferLength);
+			else
+				r=SetRxBufferSize((TInt)a1);
+			break;
+		// ***************************************
+
+		case RBusDevComm::EControlMinTurnaroundTime:
+			r = iTurnaroundMicroSeconds;			// used saved value
+			break;
+
+		case RBusDevComm::EControlSetMinTurnaroundTime:
+				{
+				if (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 
+ 					// then the timer is adjusted depending on the new value and if any
+                    // write request has been queued, transmission will proceed after the timer has expired.
+					if(iTurnaroundTimerStartTimeValid == 0)
+						{	
+						 iTurnaroundTimerStartTimeValid = 1;
+						 iTurnaroundTimerStartTime = NKern::TickCount();
+						}
+				    if(iTurnaroundTimerStartTimeValid != 2)
+						TurnaroundClear();
+					if(newTurnaroundMilliSeconds > 0)
+						{
+						r = TurnaroundSet(newTurnaroundMilliSeconds);
+						}
+					}
+				}
+			break;
+		default:
+			r=KErrNotSupported;
+			}
+		return(r);
+		}
+
+void DChannelComm::DoPowerUp()
+//
+// Called at switch on and upon Opening.
+//
+    {
+	LOG(("DoPowerUp()"));
+	__KTRACE_OPT(KPOWER,Kern::Printf("DChannelComm::DoPowerUp()"));
+
+	ResetBuffers(ETrue);
+	iRxOutstanding=EFalse;
+	iNotifyData=EFalse;
+	iTxOutstanding=EFalse;
+    iTxDesPos=0;
+    iFlags=0;
+
+	// Cancel turnaround
+	iTurnaroundMinMilliSeconds = 0;
+	iTurnaroundTimerRunning = EFalse;
+	iTurnaroundTransmitDelayed = EFalse;
+
+	// cancel any DFCs/timers
+	iRxDrainDfc.Cancel();
+	iRxCompleteDfc.Cancel();
+	iTxFillDfc.Cancel();
+	iTxCompleteDfc.Cancel();
+	iTimer.Cancel();
+	iTurnaroundTimer.Cancel();
+	iTurnaroundDfc.Cancel();
+	iTimerDfc.Cancel();
+	iSigNotifyDfc.Cancel();
+
+	Complete(EAll, KErrAbort);
+	if (!Kern::PowerGood())
+		return;
+	TUint hand=iConfig.iHandshake;
+	if (hand&(KConfigFreeRTS|KConfigFreeDTR))
+		{
+		Start();
+		if (!Kern::PowerGood())
+			return;
+		if (hand&KConfigFreeRTS)
+			{
+			if (iSignals&KSignalRTS)
+				SetSignals(KSignalRTS,0);
+			else
+				SetSignals(0,KSignalRTS);
+			}
+		if (!Kern::PowerGood())
+			return;
+		if (hand&KConfigFreeDTR)
+			{
+			if (iSignals&KSignalDTR)
+				SetSignals(KSignalDTR,0);
+			else
+				SetSignals(0,KSignalDTR);
+			}
+		CheckOutputHeld();
+		}
+	else
+		{
+		if (iStatus==EActive)
+			iStatus=EOpen;
+		}
+	}
+
+void DChannelComm::PowerUpDfc(TAny* aPtr)
+	{
+	
+	DChannelComm* d = (DChannelComm*)aPtr;
+	__PM_ASSERT(d->iStandby);
+	if (d->iStatus != EClosed)
+		d->DoPowerUp();
+	else
+		// There is racing Close(): driver was already closed (ECloseMsg) but the DPowerHandler was not destroyed yet.
+		{}
+	d->iStandby = EFalse;
+	d->iPowerHandler->PowerUpDone();
+	if (d->iMsgHeld)
+		{
+		__PM_ASSERT(d->iStatus != EClosed);
+		d->iMsgHeld = EFalse;
+		d->HandleMsg(d->iMsgQ.iMessage);
+		}
+	}
+
+void DChannelComm::PowerDownDfc(TAny* aPtr)
+	{
+	DChannelComm* d = (DChannelComm*)aPtr;
+	__PM_ASSERT(!d->iStandby);
+	d->iStandby = ETrue;
+	if (d->iStatus != EClosed)
+		d->Shutdown();
+	else
+		// There is racing Close(): driver was already closed (ECloseMsg) but the DPowerHandler was not destroyed yet.
+		{}
+	d->iPowerHandler->PowerDownDone();
+	}
+
+DCommPowerHandler::DCommPowerHandler(DChannelComm* aChannel)
+	:	DPowerHandler(KLddName), 
+		iChannel(aChannel)
+	{
+	}
+
+void DCommPowerHandler::PowerUp()
+	{
+	iChannel->iPowerUpDfc.Enque();
+	}
+
+void DCommPowerHandler::PowerDown(TPowerState)
+	{
+	iChannel->iPowerDownDfc.Enque();
+	}
+
+void DChannelComm::FinishBreak(TAny* aSelf)
+	{
+	DChannelComm* self = (DChannelComm*)aSelf;
+	self->QueueFinishBreakDfc();
+	}
+
+void DChannelComm::QueueFinishBreakDfc()
+	{
+	iBreakDfc.Enque();
+	}
+	
+	
+void DChannelComm::FinishBreakDfc(TAny* aSelf)
+	{
+	DChannelComm* self = (DChannelComm*)aSelf;
+	self->FinishBreakImplementation(KErrNone);
+	}
+
+void DChannelComm::FinishBreakImplementation(TInt aError)
+	{
+	if (iStatus==EClosed)
+		{
+		Complete(EBreak, KErrNotReady);
+		}
+	else
+		{
+		BreakOff();
+		Complete(EBreak, aError);
+		}
+
+	// re-setup transmission if needed, for writes after a break
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	if (iBreakDelayedTx)
+		{
+		iBreakDelayedTx = EFalse;		// protected -> prevent reentrant ISR
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+		RestartDelayedTransmission();
+		}
+	else
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+	}
+void DChannelComm::RestartDelayedTransmission()
+	{
+	LOG(("RestartDelayedTransmission()"));
+	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
+	TBool completeTx=EFalse;
+	
+	iBreakDelayedTx = EFalse;		// protected -> prevent reentrant ISR
+	__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+
+	if (iStatus==EClosed)
+		{
+		irq = __SPIN_LOCK_IRQSAVE(iLock);
+		iTxError = KErrNotReady;		// protected -> changed in signals ISR
+		completeTx = ETrue;
+		}
+
+	else if(IsLineFail(iFailSignals))	// have signals changed in the meantime?
+		{
+		irq = __SPIN_LOCK_IRQSAVE(iLock);
+		iTxError = KErrCommsLineFail;	// protected -> changed in signals ISR
+		completeTx = ETrue;
+		}
+
+	else
+		{
+		InitiateWrite();
+		}
+
+
+	if(completeTx)
+		{
+		iTxError = KErrNone;
+		__SPIN_UNLOCK_IRQRESTORE(iLock, irq);
+		Complete(ETx, iTxError);
+		}
+	}