kernel/eka/drivers/ecomm/d_comm.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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);
		}
	}