--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolsandutils/wintunnel/src_beech/d_comm.cpp Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,1355 @@
+// 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 "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:
+// Evil communications corrupt good manners.
+// 1 corinthians xv. 33.
+//
+//
+
+
+#include <k32std.h>
+#include "d_comm.h"
+#include <e32hal.h>
+
+const TInt KIdleTimeoutPeriod=20*1000000; // 20 seconds
+const TUint KXoffSignal=0x80000000;
+//
+const TInt KInputHeldFree=(-1);
+const TInt KInputHeld=(-2);
+//
+const TUint KTransmitting=0x01;
+const TUint KBreaking=0x02;
+const TUint KBreakPending=0x04;
+//
+enum TPanic
+ {
+ ESetConfigWhileRequestPending,
+ ESetSignalsSetAndClear,
+ EResetBuffers,
+ ESetReceiveBufferLength,
+// EDoubleTxBufFill,
+ };
+
+EXPORT_C DLogicalDevice *CreateLogicalDevice()
+//
+// Create a new device
+//
+ {
+ return(new DDeviceComm);
+ }
+
+DDeviceComm::DDeviceComm()
+//
+// Constructor
+//
+ {
+ iParseMask=KDeviceAllowAll;
+ iUnitsMask=0xffffffff; // Leave units decision to the driver
+ iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+ }
+
+TInt DDeviceComm::Install()
+//
+// Install the device driver.
+//
+ {
+ TPtrC name=_L("Comm");
+ return(SetName(&name));
+ }
+
+void DDeviceComm::GetCaps(TDes8 &aDes) const
+//
+// Return the Comm capabilities.
+//
+ {
+
+ TCapsDevCommV01 b;
+ b.version=iVersion;
+ aDes.FillZ(aDes.MaxLength());
+ aDes.Copy((TUint8 *)&b,Min(aDes.MaxLength(),sizeof(b)));
+ }
+
+DLogicalChannel *DDeviceComm::CreateL()
+//
+// Create a channel on the device.
+//
+ {
+
+ return(new(ELeave) DChannelComm(this));
+ }
+
+TInt DChannelComm::CallDfc(TAny* aDChannelComm)
+//
+// Dfc call back - cast the pointer to a DChannel comm and call DoDfc
+//
+ {
+ ((DChannelComm *)aDChannelComm)->DfcHandler();
+ return KErrNone;
+ }
+
+//
+// Comms power handler
+//
+// Active tx requests keep power requirement up.
+// Completed tx requests keep power requirement up for KIdleTimeoutPeriod.
+// Rx requests don't effect power requirement
+//
+DCommPowerHandler::DCommPowerHandler(DChannelComm *aLdd) : iLdd(aLdd)
+ {}
+
+void DCommPowerHandler::RequestPending()
+//
+// Tx request made
+//
+ {
+ iTimer.Cancel();
+ if (iRequirement == 0)
+ SetRequirement(1); /* EPowerCpu */
+ }
+
+void DCommPowerHandler::RequestComplete()
+//
+// Tx request completed, set the timer
+//
+ {
+ iTimer.Cancel();
+ iTimer.OneShotInMicroSeconds(TTimeIntervalMicroSeconds32(KIdleTimeoutPeriod), DCommPowerHandler::Timeout, this);
+ }
+
+void DCommPowerHandler::Timeout(TAny *aHandler, TInt)
+//
+// Timeout following last Tx request (in DFC)
+//
+ {
+
+ DCommPowerHandler& handler=*(DCommPowerHandler*)aHandler;
+ handler.SetRequirement(0); // EPowerNone
+ handler.iLdd->DoPowerDown();
+ handler.iLdd->ResetDevice();
+ handler.iLdd->CompleteAll(KErrAbort); // Complete all outstanding client requests
+ }
+
+TInt DCommPowerHandler::DoPowerOn()
+//
+// Machine power up event
+// Serial driver ignores machine power up events and instead powers up the
+// device in response to user requests
+//
+ {
+ return(KErrNone);
+ }
+
+void DCommPowerHandler::DoPowerEmergencyStandby()
+//
+// Machine emergency power down event
+// Can't ignore these events - need to power down the device
+//
+ {
+ iLdd->DoEmergencyPowerDown();
+ }
+
+void DCommPowerHandler::DoPowerStandby()
+//
+// Machine normal power down event
+// Serial driver ignores machine normal power down events and instead uses an
+// inactivity timer on Tx requests to control power down.
+//
+ {
+ }
+
+#pragma warning( disable : 4705 ) // statement has no effect
+#pragma warning( disable : 4355 ) // this used in intializer list
+DChannelComm::DChannelComm(DLogicalDevice *aDevice)
+//
+// Constructor
+//
+: DLogicalChannel(aDevice), iDfc(TCallBack(DChannelComm::CallDfc,this))
+ {
+
+//
+// Require power notifications and 3 valid requests
+//
+ SetBehaviour(RBusDevComm::ERequestReadCancel|RBusDevComm::ERequestWriteCancel|RBusDevComm::ERequestBreakCancel|RBusDevComm::ERequestNotifySignalChangeCancel);
+//
+// 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;
+// iDriver=NULL;
+ iStatus=ENotActive;
+ iInputHeld=KInputHeldFree;
+// iOutputHeld=0;
+// iReceiveOneOrMore=0;
+// iReceiveError=0;
+// iReceiveErrorLength=0;
+// iReceiveLength=0;
+// iReceiveOffset=0;
+// iTransmitLength=0;
+// iTransmitOffset=0;
+// iFlags=0;
+// iSignals=0;
+// iLowWaterMark=0;
+// iHighWaterMark=0;
+// iHalfFullMark=0;
+// iReceivePtr=NULL;
+// iTransmitPtr=NULL;
+// iRxBuf=NULL;
+// iTxBuf=NULL;
+// iIsReading=EFalse;
+// iIsWriting=EFalse;
+// iDrainingRxBuf=EFalse;
+// iFillingTxBuf=EFalse;
+// iRunningDfc=EFalse;
+// iSignalChangeNotification=EFalse;
+// iSignalChangePtr=NULL;
+// iSignalMask=0;
+// iSignalChangeInfo=0;
+// iDataAvailableNotification=EFalse;
+ }
+#pragma warning( default : 4705 )
+#pragma warning( disable : 4355 )
+
+DChannelComm::~DChannelComm()
+//
+// Destructor
+//
+ {
+ // Complete any outstanding requests
+ CompleteAll(KErrAbort);
+
+ // Power down h/w, disable interrupts
+ iPowerHandler->iTimer.Cancel();
+ iPowerHandler->PowerStandby(); // Doesn't do anything in inactivity power policy case, hence DoPowerDown() call below.
+ DoPowerDown();
+
+ // clean up the power handler
+// iPowerHandler->SetRequirement(0); // No need for this, done in DoPowerDown().
+ Power::RemovePowerHandler(*iPowerHandler);
+ delete iPowerHandler;
+
+ TInt clearMask=0;
+ if (!(iConfig.iHandshake&KConfigFreeRTS))
+ clearMask|=KSignalRTS;
+ if (!(iConfig.iHandshake&KConfigFreeDTR))
+ clearMask|=KSignalDTR;
+ iDriver->SetSignals(0,clearMask);
+
+ delete iDriver;
+
+ delete iRxBuf;
+ delete iTxBuf;
+ }
+
+void DChannelComm::DoCreateL(TInt /*aUnit*/,CBase *aDriver,const TDesC * /*anInfo*/,const TVersion &aVer)
+//
+// Create the channel from the passed info.
+//
+ {
+ iDriver=(DComm *)aDriver; // Must do this to ensure the driver is destroyed by the destructor
+ if (!User::QueryVersionSupported(TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber),aVer))
+ User::Leave(KErrNotSupported);
+ // get power managed
+ iPowerHandler=new (ELeave) DCommPowerHandler(this);
+ User::LeaveIfError(Power::AddPowerHandler(*iPowerHandler));
+// iRxBuf=new(ELeave) CCirBuf<TInt>;
+// iTxBuf=new(ELeave) CCirBuffer;
+ iTxBuf=new(ELeave) CCommTxBuf;
+ iRxBuf=new(ELeave) CCommRxBuf;
+ User::LeaveIfError(SetRxBufferSize(KDefaultRxBufferSize));
+ iTxBuf->SetLengthL(KTxBufferSize);
+ ((DComm *)aDriver)->SetComm(this); // Rog
+ iDriver->CheckConfig(iConfig);
+ StateIsr(iDriver->Signals());
+
+ iPowerHandler->PowerOn(); // Ask the PowerManager to power us up
+ }
+
+void DChannelComm::DfcHandler()
+//
+// Called as a Dfc. Handles all buffer draining and filling and message completions.
+//
+ {
+ iDriver->DisableInterrupts();
+ while (iDfcRequest!=0)
+ {
+ if (iDfcRequest & EDrainRxBufferRequired)
+ {
+#ifdef _DEBUG_DEVCOMM
+ iDfcHandlerSeq = iRxBuf->iRemSeqNum.Int();
+#endif
+ iDfcRequest &= ~EDrainRxBufferRequired;
+ iDriver->EnableInterrupts();
+ if (!iDrainingRxBuf)
+ DoDrainRxBuffer();
+ iDriver->DisableInterrupts();
+ continue;
+ }
+ if (iDfcRequest & ECompleteWrite)
+ {
+ iDfcRequest &= ~ECompleteWrite;
+ iDriver->EnableInterrupts();
+ if (iIsWriting)
+ {
+ iIsWriting = EFalse;
+ iWriteZero = EFalse;
+ if (iIsClientWriting)
+ Complete(RBusDevComm::ERequestWrite,iWriteError);
+ iIsClientWriting = EFalse;
+ iWriteError = KErrNone;
+ }
+ iDriver->DisableInterrupts();
+ continue;
+ }
+ else if (iDfcRequest & EEarlyCompleteWrite)
+ {
+ iDfcRequest &= ~EEarlyCompleteWrite;
+ iDriver->EnableInterrupts();
+ if (iIsClientWriting)
+ {
+ iIsClientWriting = EFalse;
+ Complete(RBusDevComm::ERequestWrite,iWriteError);
+ iWriteError = KErrNone;
+ }
+ iDriver->DisableInterrupts();
+ continue;
+ }
+ if (iDfcRequest & ECompleteEmergency)
+ {
+ iDfcRequest &= ~ECompleteEmergency;
+ ResetDevice();
+ CompleteAll(KErrBadPower);
+ continue;
+ }
+ if (iDfcRequest & EFillTxBufferRequired)
+ {
+ iDfcRequest &= ~EFillTxBufferRequired;
+ iDriver->EnableInterrupts();
+ if (!iFillingTxBuf)
+ DoFillTxBuffer();
+ iDriver->DisableInterrupts();
+ continue;
+ }
+ if (iDfcRequest & ECompleteSignalChange)
+ {
+ iDfcRequest &= ~ECompleteSignalChange;
+ iThread->Write(iSignalChangePtr,(TUint8*)&iSignalChangeInfo,(TInt)sizeof(TUint));
+ iSignalChangeNotification=EFalse;
+ Complete(RBusDevComm::ERequestNotifySignalChange);
+ continue;
+ }
+ if (iDfcRequest & ECompleteDataAvailable)
+ {
+ iDfcRequest &= ~ECompleteDataAvailable;
+ iDataAvailableNotification=EFalse;
+ Complete(RBusDevComm::ERequestRead);
+ continue;
+ }
+ }
+#ifdef _DEBUG_DEVCOMM
+ --iDfcCount;
+#endif
+ iRunningDfc=EFalse;
+ iPowerHandler->RequestComplete();
+ iDriver->EnableInterrupts();
+ }
+
+void DChannelComm::RestoreDtrRrs()
+//
+// Check if driver is configured not to auto control RTS/DTR and restore state
+// of these signals acording to current config. (as specified by driver
+// client) if necessary
+//
+ {
+
+ TUint hand=iConfig.iHandshake;
+ if ((hand&KConfigFreeRTS))
+ {
+ if (iSignals&KSignalRTS)
+ iDriver->SetSignals(KSignalRTS,0);
+ else
+ iDriver->SetSignals(0,KSignalRTS);
+ }
+ if (!iPowerHandler->PowerGood())
+ return;
+ if (hand&KConfigFreeDTR)
+ {
+ if (iSignals&KSignalDTR)
+ iDriver->SetSignals(KSignalDTR,0);
+ else
+ iDriver->SetSignals(0,KSignalDTR);
+ }
+ }
+
+void DChannelComm::Start()
+//
+// Start the driver receiving.
+//
+ {
+
+ // If waiting for driver to be closed then just return
+ if (iStatus==EClosed)
+ return;
+
+ if (iStatus!=EActive)
+ ResetBuffers(); // Reset RX/TX buffers
+
+ iDriver->Configure(iConfig);
+ iDriver->Start();
+ if (iConfig.iHandshake & KConfigSendXoff && iInputHeld>=0)
+ EnableTransmit(); // Send XOn if there is one
+
+ if (iStatus!=EActive)
+ {
+ // If driver configured not to auto control RTS/DTR then restore state of
+ // these signals acording to current config. (as specified by driver client).
+ TUint hand=iConfig.iHandshake;
+ if (hand&(KConfigFreeRTS|KConfigFreeDTR))
+ RestoreDtrRrs();
+ }
+ iStatus=EActive;
+ }
+
+void DChannelComm::Stop(TStopMode aMode)
+//
+// Stop the driver.
+//
+ {
+ iDriver->Stop(aMode);
+ }
+
+void DChannelComm::BreakOn()
+//
+// Start the driver breaking.
+//
+ {
+
+ if (iFlags&KTransmitting)
+ iFlags|=KBreakPending;
+ else
+ {
+ iFlags&=(~KBreakPending);
+ iFlags|=KBreaking;
+ iDriver->Break(ETrue);
+ }
+ }
+
+void DChannelComm::BreakOff()
+//
+// Stop the driver breaking.
+//
+ {
+
+ iDriver->Break(EFalse);
+ iFlags&=(~(KBreakPending|KBreaking));
+ }
+
+void DChannelComm::EnableTransmit()
+//
+// Make sure we are transmitting
+//
+ {
+
+ if ((iFlags & KTransmitting)==0)
+ {
+ iFlags |= KTransmitting; // Signal the fact the we are transmitting
+ iDriver->EnableTransmit(); // Start transmitting
+ }
+ }
+
+TInt DChannelComm::SetRxBufferSize(TInt aSize)
+//
+// Set the receive buffer size.
+//
+ {
+
+ TRAPD(r,iRxBuf->SetLengthL(aSize));
+ if (r==KErrNone)
+ {
+ iLowWaterMark=(aSize>>2); // 25 %
+ iHalfFullMark=(aSize>>1); // 50 %
+ if (iConfig.iParityError & KConfigXonXoffDebug)
+ {
+ iHighWaterMark=iHalfFullMark-5;
+ }
+ else
+ iHighWaterMark=aSize-iLowWaterMark; // 75%
+ }
+ return(r);
+ }
+
+void DChannelComm::ResetBuffers()
+//
+// Reset the receive and transmit buffers.
+//
+ {
+
+ iIsWriting=EFalse;
+ iRxBuf->Reset();
+ iTxBuf->Reset();
+
+ iReceiveError=KErrNone;
+ if (iStatus==EActive)
+ {
+ if ((iConfig.iHandshake & KConfigFreeRTS)==0)
+ iDriver->SetSignals(KSignalRTS,0); // Assert RTS
+ if ((iConfig.iHandshake & KConfigFreeDTR)==0)
+ iDriver->SetSignals(KSignalDTR,0); // Assert DTR
+ if (iConfig.iHandshake&KConfigSendXoff) // Doing input XON/XOFF
+ {
+ iInputHeld=iConfig.iXonChar; // set up to send Xon
+ EnableTransmit(); // Make sure we are transmitting
+ }
+ else
+ iInputHeld=KInputHeldFree;
+ }
+ iReceiveErrorLength=0;
+ }
+
+TBool DChannelComm::IsLineFail(TUint aHandshake)
+//
+// True if any line fail errors occured.
+//
+ {
+
+ if ((iSignals&KSignalCTS)==0 &&
+ (aHandshake&(KConfigObeyCTS|KConfigFailCTS))==(KConfigObeyCTS|KConfigFailCTS) ||
+ (iSignals&KSignalDSR)==0 &&
+ (aHandshake&(KConfigObeyDSR|KConfigFailDSR))==(KConfigObeyDSR|KConfigFailDSR) ||
+ (iSignals&KSignalDCD)==0 &&
+ (aHandshake&(KConfigObeyDCD|KConfigFailDCD))==(KConfigObeyDCD|KConfigFailDCD))
+ return(TRUE);
+ return(FALSE);
+ }
+
+
+void DChannelComm::DoDrainRxBuffer()
+//
+// Drain the receive buffer
+//
+ {
+ iDriver->DisableInterrupts();
+ if (!IsReading())
+ {
+ iDriver->EnableInterrupts();
+ return;
+ }
+ if (iDrainingRxBuf)
+ {
+ iDriver->EnableInterrupts();
+ return;
+ }
+ iDrainingRxBuf = ETrue;
+
+#ifdef _DEBUG_DEVCOMM
+ iDoDrainSeq = iRxBuf->iRemSeqNum.Int();
+#endif
+
+ TUint status;
+ TInt res = iRxBuf->ClientWrite(status, iDriver, iThread, iReceivePtr, iReceiveLength, iReceiveOffset, KChunkShiftBy0);
+ if (res<0 && iReceiveError==KErrNone) // Buffer empty
+ {
+ iDrainingRxBuf = EFalse;
+ iDriver->EnableInterrupts();
+ return;
+ }
+
+ if (res>0 || (status & KReceiveIsrMaskComplete) || iReceiveError!=KErrNone) // Complete client op
+ {
+ if (iReceiveError==KErrNone && (status & KReceiveIsrMaskError))
+ {
+ if (status & KReceiveIsrOverrunError)
+ iReceiveError = KErrCommsOverrun;
+ else if (status & KReceiveIsrFrameError)
+ iReceiveError = KErrCommsFrame;
+ else if ((status & KReceiveIsrParityError) && !(iConfig.iParityError & KConfigParityErrorIgnore))
+ iReceiveError = KErrCommsParity;
+ }
+
+ Complete(RBusDevComm::ERequestRead, iReceiveError);
+ iReceiveError = KErrNone;
+ iIsReading=EFalse;
+ }
+
+ if (iRxBuf->Count()<=iLowWaterMark && iInputHeld==KInputHeld) // At or below the low water mark and input held
+ {
+ if ((iConfig.iHandshake & KConfigFreeRTS)==0)
+ iDriver->SetSignals(KSignalRTS,0); // Assert RTS
+ if ((iConfig.iHandshake & KConfigFreeDTR)==0)
+ iDriver->SetSignals(KSignalDTR,0); // Assert DTR
+ if (iConfig.iHandshake&KConfigSendXoff) // Doing input XON/XOFF
+ {
+ iInputHeld=iConfig.iXonChar; // set up to send Xon
+ EnableTransmit(); // Make sure we are transmitting
+ }
+ else
+ iInputHeld=KInputHeldFree; // Mark input free
+ }
+ iDrainingRxBuf = EFalse;
+ iDriver->EnableInterrupts();
+ }
+
+
+void DChannelComm::DoFillTxBuffer()
+//
+// Fill the transmit buffer
+//
+ {
+ iDriver->DisableInterrupts();
+ if (iFillingTxBuf)
+ {
+ iDriver->EnableInterrupts();
+ return;
+ }
+ iFillingTxBuf=ETrue;
+ iDriver->EnableInterrupts();
+
+ if (iTxBuf->ClientRead(iDriver, iThread, iTransmitPtr, iTransmitLength, iTransmitOffset, KChunkShiftBy0)==KErrNone)
+ EnableTransmit();
+
+ if (iIsClientWriting && (iTransmitPtr==NULL || iTransmitLength==0) && (iConfig.iHandshake & KConfigWriteBufferedComplete))
+ EarlyCompleteWrite();
+ iFillingTxBuf=EFalse;
+ }
+
+void DChannelComm::ReceiveIsr(TUint aChar)
+//
+// Handle a received character from the ISR.
+//
+ {
+
+ if (iDataAvailableNotification)
+ CompleteDataAvailable();
+
+ if (iConfig.iHandshake & KConfigObeyXoff) // Doing output XON/XOFF
+ {
+ if (aChar==iConfig.iXonChar) // Output now allowed
+ { // May get multiple XON's in quick succession
+ iOutputHeld &= ~KXoffSignal; // Mark output ok. for XON/XOFF
+#ifdef _DEBUG_DEVCOMM
+ iRxXon++;
+#endif
+ EnableTransmit();
+ return;
+ }
+ if (aChar==iConfig.iXoffChar) // Output now disallowed
+ {
+#ifdef _DEBUG_DEVCOMM
+ iRxXoff++;
+#endif
+ iOutputHeld |= KXoffSignal; // Mark output held for XON/XOFF
+ DrainRxBuffer();
+ return;
+ }
+ }
+
+#ifdef _DEBUG_DEVCOMM
+ iRxChars++;
+#endif
+
+ TBool doDrainRxBuffer=EFalse;
+
+ TInt count = iRxBuf->Count();
+
+ if (count>=iHighWaterMark && (count & 1)) // At or above the high water mark send xoff every other character
+ {
+ // Copes with the S/W and H/W handshaking
+ if ((iConfig.iHandshake & KConfigFreeRTS)==0) // RTS enabled
+ iDriver->SetSignals(0,KSignalRTS); // Drop RTS
+ else if ((iConfig.iHandshake & KConfigFreeDTR)==0) // DTR enabled, but not RTS
+ iDriver->SetSignals(0,KSignalDTR); // Drop DTR
+
+ if (iConfig.iHandshake & KConfigSendXoff) // Doing input XON/XOFF
+ {
+ iInputHeld=iConfig.iXoffChar; // Mark input held
+ EnableTransmit(); // Make sure we are transmitting
+ }
+ else
+ iInputHeld=KInputHeld; // Mark input held
+
+ doDrainRxBuffer=ETrue;
+ }
+
+ // Check for parity errors and replace char if so configured.
+ if (aChar & KReceiveIsrParityError)
+ {
+ // Replace bad character
+ if (iConfig.iParityError==KConfigParityErrorReplaceChar)
+ aChar = aChar & ~(0xff|KReceiveIsrParityError) | iConfig.iParityErrorChar;
+ // Ignore parity error
+ if (iConfig.iParityError==KConfigParityErrorIgnore)
+ aChar = aChar & ~KReceiveIsrParityError;
+ }
+
+ // Check for terminating character
+ for (TInt i=0; i<iConfig.iTerminatorCount; i++)
+ {
+ if (iConfig.iTerminator[i]==aChar)
+ {
+ aChar |= KReceiveIsrTermChar;
+ doDrainRxBuffer=ETrue;
+ break;
+ }
+ }
+
+ TInt e;
+ if (e = iRxBuf->PutChar(aChar), e!=0)
+ {
+ if (e<0)
+ {
+ if (e==KErrOverflow)
+ e = KErrCommsOverrun;
+ iReceiveError = e;
+ }
+ doDrainRxBuffer = ETrue;
+ }
+
+ // Determine if the request will be completed by the arrival of the character
+ if (IsReading() && iReceiveLength>0)
+ {
+ // If the buffer is full enough to complete the request
+ // or over the half full mark the drain the buffer
+ TInt count=iRxBuf->Count();
+ if (iReceiveLength<=count || count>=iHalfFullMark || (aChar & KReceiveIsrMaskComplete))
+ doDrainRxBuffer=ETrue;
+ }
+
+ if (doDrainRxBuffer)
+ DrainRxBuffer();
+ }
+
+
+TInt DChannelComm::TransmitIsr()
+//
+// Return the next character to be transmitted to the ISR
+//
+ {
+
+ TInt tChar=KTransmitIrqEmpty; // No character to be sent
+ if (iInputHeld>=0) // Control character to send
+ {
+ tChar=iInputHeld; // Send the control character
+#ifdef _DEBUG_DEVCOMM
+ if (tChar==iConfig.iXonChar)
+ iTxXon++;
+ else
+ iTxXoff++;
+#endif
+ iInputHeld=(tChar==iConfig.iXonChar ? KInputHeldFree : KInputHeld);
+ }
+ else if (iOutputHeld==0) // Is the output free
+ {
+ if (IsWriting()) // Anything to be transmitted
+ {
+ tChar=iTxBuf->Get();
+ if (tChar<0 && iTransmitLength==0) // No characters left to send
+ {
+ tChar=KTransmitIrqEmpty;
+ if (iWriteZero)
+ {
+ TUint stat = iDriver->Signals();
+ stat &= (KSignalCTS|KSignalDSR|KSignalDCD|KXoffSignal);
+ stat ^= (KSignalCTS|KSignalDSR|KSignalDCD);
+ if (!(iConfig.iHandshake & KConfigObeyCTS)) // If ignoring CTS
+ stat &= (~KSignalCTS);
+ if (!(iConfig.iHandshake & KConfigObeyDSR)) // If ignoring DSR
+ stat &= (~KSignalDSR);
+ if (!(iConfig.iHandshake & KConfigObeyDCD)) // If ignoring DCD
+ stat &= (~KSignalDCD);
+ if (iOutputHeld & KXoffSignal)
+ stat |= KXoffSignal; // Leave the xon/xoff handshake bit
+ if ((stat & ~KXoffSignal)==0)
+ CompleteWrite();
+ }
+ else
+ {
+ if (!(iConfig.iHandshake&KConfigWriteBufferedComplete))
+ CompleteWrite();
+ }
+ }
+ else if (iTransmitLength!=0 && iTxBuf->Count()<(KTxBufferSize>>1)) // Less than half full
+ FillTxBuffer();
+#ifdef _DEBUG_DEVCOMM
+ if (tChar!=KTransmitIrqEmpty)
+ iTxChars++;
+#endif
+ }
+ }
+
+ if (tChar!=KTransmitIrqEmpty) // Character to be sent
+ iFlags|=KTransmitting;
+ else
+ iFlags&=(~KTransmitting);
+
+ return(tChar);
+ }
+
+void DChannelComm::StateIsr(TUint aStatus)
+//
+// Handle a state change from the ISR
+//
+ {
+ if (iSignalChangeNotification && ((iSignals^aStatus)&iSignalMask))
+ {
+ iSignalChangeInfo=(((iSignals^aStatus)&iSignalMask)<<12)|(aStatus&iSignalMask);
+ CompleteSignalChange();
+ }
+ iSignals=aStatus; // Update the status
+ TUint handshake=iConfig.iHandshake; // Get the handshake characteristic
+
+ if (IsLineFail(handshake))
+ {
+// CompleteAll(KErrCommsLineFail); // Can't just complete reads from interrupts.
+// iIsReading=EFalse;
+ iReceiveError=KErrCommsLineFail;
+ DrainRxBuffer();
+
+ if (IsWriting())
+ {
+ iWriteError = KErrCommsLineFail;
+ CompleteWrite();
+ }
+ }
+
+//
+// Now we must determine if output is to be held
+//
+ aStatus &= (KSignalCTS|KSignalDSR|KSignalDCD|KXoffSignal);
+ aStatus ^= (KSignalCTS|KSignalDSR|KSignalDCD);
+
+ if (!(handshake & KConfigObeyCTS)) // If ignoring CTS
+ aStatus &= (~KSignalCTS);
+
+ if (!(handshake & KConfigObeyDSR)) // If ignoring DSR
+ aStatus &= (~KSignalDSR);
+
+ if (!(handshake & KConfigObeyDCD)) // If ignoring DCD
+ aStatus &= (~KSignalDCD);
+
+ if (iOutputHeld & KXoffSignal)
+ aStatus |= KXoffSignal; // Leave the xon/xoff handshake bit
+
+//
+// For write zero, we complete if the lines indicate we could write....
+//
+ if (iWriteZero && (aStatus & ~KXoffSignal)==0)
+ {
+ if (iIsClientWriting && iTxBuf->Count()==0)
+ {
+ CompleteWrite();
+ return;
+ }
+ }
+
+//
+// If request outstanding AND we were holding AND not held anymore
+//
+ if (aStatus==0 && /*iTransmitPtr!=0*/ IsWriting() /*&& iOutputHeld!=0*/)
+ {
+ iOutputHeld=0; // Not holding any more
+ EnableTransmit(); // Start transmitting again
+ }
+ else
+ iOutputHeld=aStatus; // Set the held bits
+ }
+
+
+void DChannelComm::DoCancel(TInt aReqNo)
+//
+// Cancel an outstanding request.
+//
+ {
+
+ switch (aReqNo)
+ {
+ case RBusDevComm::ERequestRead:
+ iIsReading=EFalse;
+ iDataAvailableNotification=EFalse;
+ break;
+ case RBusDevComm::ERequestWrite:
+ iIsClientWriting=EFalse;
+ iWriteZero=EFalse;
+ iIsWriting=EFalse;
+ iTxBuf->Reset();
+ break;
+ case RBusDevComm::ERequestBreak:
+ BreakOff();
+ break;
+ case RBusDevComm::ERequestNotifySignalChange:
+ iSignalChangeNotification=EFalse;
+ break;
+ }
+ }
+
+void DChannelComm::DoRequest(TInt aReqNo,TAny *a1,TAny *a2)
+//
+// Async requests.
+//
+ {
+
+ TBool dataAvailReq=aReqNo&KDataAvailableNotifyFlag;
+ aReqNo&=(~KChanRequestNoReservedMask); // Mask off device specific flags
+
+ //
+ // First check if we have started
+ //
+ if (iStatus==ENotActive)
+ {
+ Start();
+ if (!(iConfig.iHandshake & KConfigFreeDTR))
+ iDriver->SetSignals(KSignalDTR,0); // Assert DTR
+ if (!(iConfig.iHandshake & KConfigFreeRTS))
+ iDriver->SetSignals(KSignalRTS,0); // Assert RTS
+ if (iConfig.iHandshake & KConfigSendXoff)
+ iInputHeld = iConfig.iXonChar;
+ else
+ iInputHeld = KInputHeldFree;
+ }
+
+ //
+ // Next we check for a line fail
+ //
+ if (IsLineFail(iConfig.iHandshake))
+ {
+ Complete(aReqNo,KErrCommsLineFail);
+ return;
+ }
+
+ //
+ // Now we can dispatch the request
+ //
+ TInt len;
+ switch (aReqNo)
+ {
+ case RBusDevComm::ERequestRead:
+ {
+ if (dataAvailReq)
+ {
+ iPowerHandler->RequestPending();
+ iDataAvailableNotification=ETrue;
+ }
+ else
+ {
+ iDriver->DisableInterrupts();
+ iReceivePtr=(TUint8 *)a1;
+ len=(*((TInt *)a2));
+ if (len<0)
+ {
+ iReceiveOneOrMore=TRUE;
+ iReceiveLength=Min(-len,iRxBuf->Count());
+ if (iReceiveLength==0)
+ iReceiveLength=1;
+ }
+ else
+ {
+ TInt maxLength=iThread->GetDesMaxLength(a1);
+ if(len>maxLength || maxLength<0)
+ {
+ iDriver->EnableInterrupts();
+ Complete(RBusDevComm::ERequestRead,KErrGeneral);
+ break;
+ }
+ iReceiveOneOrMore=FALSE;
+ iReceiveLength=len;
+ if (iReceiveLength==0)
+ {
+ iDriver->EnableInterrupts();
+ Complete(RBusDevComm::ERequestRead);
+ break;
+ }
+ }
+ if (iReceiveError && iReceiveLength>iReceiveErrorLength)
+ iReceiveLength=iReceiveErrorLength;
+ iReceiveOffset=0;
+ iIsReading=ETrue;
+ iPowerHandler->RequestPending();
+ iDriver->EnableInterrupts();
+ if(iConfig.iHandshake&KConfigSendXoff)
+ {
+ iInputHeld=iConfig.iXonChar;
+ EnableTransmit();
+ }
+
+ DoDrainRxBuffer();
+ }
+ }
+ break;
+ case RBusDevComm::ERequestWrite:
+ if (iStatus==EClosed)
+ {
+ Complete(aReqNo,KErrNotReady);
+ iPowerHandler->RequestComplete();
+ break;
+ }
+ iPowerHandler->RequestPending();
+ iDriver->DisableInterrupts();
+ if ((iTransmitLength=(*((TInt *)a2)))==0)
+ {
+ iWriteZero=ETrue;
+ iIsWriting=ETrue;
+ iIsClientWriting=ETrue;
+ iDriver->EnableInterrupts();
+ }
+ else
+ {
+ iTransmitPtr=(TUint8 *)a1;
+ iTransmitOffset=0;
+ iIsClientWriting=ETrue;
+ if((iFlags&KTransmitting) && iIsWriting) // let the transmit isr deal with it
+ {
+ iDriver->EnableInterrupts();
+ StateIsr(iDriver->Signals());
+ break;
+ }
+ iIsWriting=EFalse;
+ iDriver->EnableInterrupts();
+ DoFillTxBuffer();
+ iIsWriting=ETrue;
+ }
+ StateIsr(iDriver->Signals());
+ break;
+ case RBusDevComm::ERequestBreak:
+ Complete(aReqNo,KErrNotSupported);
+ break;
+ case RBusDevComm::ERequestNotifySignalChange:
+ iSignalChangePtr=(TUint*)a1;
+ iSignalMask=*(TUint*)a2;
+ iSignalChangeNotification=ETrue;
+ break;
+ }
+ }
+
+TInt DChannelComm::DoControl(TInt aFunction,TAny *a1,TAny *a2)
+//
+// Sync requests.
+//
+ {
+
+ TCommConfigV01 c;
+ TInt len;
+ TInt r=KErrNone;
+
+ TBool restart = EFalse;
+ TBool purge = EFalse;
+ TBool rescan = EFalse;
+
+ switch (aFunction)
+ {
+ case RBusDevComm::EControlConfig:
+ ((TDes8 *)a1)->FillZ(((TDes8 *)a1)->MaxLength());
+ len=Min(((TDes8 *)a1)->MaxLength(),sizeof(iConfig));
+ ((TDes8 *)a1)->Copy((TUint8 *)&iConfig,len);
+ break;
+ case RBusDevComm::EControlSetConfig:
+ if (AreAnyPending())
+// iThread->Panic(_L("D32COMM"),ESetConfigWhileRequestPending);
+ Kern::PanicCurrentThread(_L("D32COMM"), ESetConfigWhileRequestPending);
+ else
+ {
+ Mem::FillZ(&c,sizeof(c));
+ len=Min(((TDesC8 *)a1)->Length(),sizeof(c));
+ Mem::Copy(&c,((TDesC8 *)a1)->Ptr(),len);
+ if(c.iTerminatorCount>KConfigMaxTerminators)
+ {
+ r=KErrNotSupported;
+ break;
+ }
+ if (c.iRate==EBpsAutobaud)
+ {
+ r=KErrNotSupported;
+ break;
+ }
+ if ((r=iDriver->Validate(c))!=KErrNone)
+ break;
+ if (IsLineFail(c.iHandshake))
+ {
+ r=KErrCommsLineFail;
+ break;
+ }
+ if (c.iSIREnable==ESIREnable)
+ {
+ c.iHandshake=0;
+ c.iStopBits=EStop1;
+ c.iDataBits=EData8;
+ }
+ 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])
+ {
+ rescan=ETrue;
+ break;
+ }
+ }
+ }
+ else
+ rescan=ETrue;
+
+ if (!rescan && c.iHandshake == iConfig.iHandshake)
+ break; // nothing to do.
+ }
+ if (iStatus==EActive && (restart || purge))
+ {
+ if (!(iConfig.iHandshake&KConfigFreeRTS))
+ iDriver->SetSignals(0,KSignalRTS); // Drop RTS
+ Stop(EStopNormal);
+ if(purge)
+ ResetBuffers();
+ iConfig=c;
+ Start();
+ if (!(iConfig.iHandshake&KConfigFreeRTS))
+ iDriver->SetSignals(KSignalRTS,0); // Assert RTS
+ iDriver->DisableInterrupts();
+ }
+ else
+ {
+ iDriver->DisableInterrupts();
+ if(purge)
+ ResetBuffers();
+ iConfig=c;
+ }
+ if(!(iConfig.iHandshake&KConfigObeyXoff))
+ iOutputHeld&=~KXoffSignal;
+ if(iConfig.iHandshake&KConfigSendXoff)
+ {
+ iInputHeld=iConfig.iXonChar;
+ iHighWaterMark=iHalfFullMark-5;
+ }
+ else
+ {
+ iInputHeld=KInputHeldFree;
+ iHighWaterMark=iRxBuf->Length()-iLowWaterMark; // 75%
+ }
+ if(iConfig.iHandshake&KConfigObeyCTS || iConfig.iHandshake&KConfigObeyDSR)
+ iInputHeld=KInputHeld;
+ iDriver->EnableInterrupts();
+
+ if (rescan)
+ iRxBuf->RescanTerminators(iDriver, iConfig.iTerminatorCount, iConfig.iTerminator);
+ }
+ break;
+ case RBusDevComm::EControlCaps:
+ iDriver->Caps(*((TDes8 *)a1));
+ break;
+ case RBusDevComm::EControlSignals:
+ r=iDriver->Signals();
+ break;
+ case RBusDevComm::EControlSetSignals:
+ if (((TUint)a1)&((TUint)a2))
+// iThread->Panic(_L("D32COMM"),ESetSignalsSetAndClear);
+ Kern::PanicCurrentThread(_L("D32COMM"), ESetSignalsSetAndClear);
+ else
+ {
+ TUint set=(TUint)a1;
+ if (iStatus==ENotActive)
+ {
+ Start();
+ if (!(iConfig.iHandshake & KConfigFreeDTR) && !((TUint)a2 & KSignalDTR))
+ set|=KSignalDTR; // Assert DTR
+ if (!(iConfig.iHandshake & KConfigFreeRTS) && !((TUint)a2 & KSignalRTS))
+ set|=KSignalRTS; // Assert RTS
+ if (iConfig.iHandshake & KConfigSendXoff)
+ iInputHeld = iConfig.iXonChar;
+ else
+ iInputHeld = KInputHeldFree;
+ }
+ iDriver->SetSignals(set,(TUint)a2);
+ iSignals=(iSignals|set)&(~(TUint)a2);
+ }
+ break;
+ case RBusDevComm::EControlQueryReceiveBuffer:
+ r=iRxBuf->Count();
+ break;
+ case RBusDevComm::EControlResetBuffers:
+ if (AreAnyPending())
+// iThread->Panic(_L("D32COMM"),EResetBuffers);
+ Kern::PanicCurrentThread(_L("D32COMM"), EResetBuffers);
+ else
+ ResetBuffers();
+ break;
+ case RBusDevComm::EControlReceiveBufferLength:
+ r=iRxBuf->Length();
+ break;
+
+ // ***************************************
+ // This one runs in the supervisor context
+ // ***************************************
+ case RBusDevComm::EControlSetReceiveBufferLength:
+ if (AreAnyPending())
+ iThread->Panic(_L("D32COMM"),ESetReceiveBufferLength);
+ else
+ r=SetRxBufferSize((TInt)a1);
+ break;
+ // ***************************************
+
+ case KChannelControlLateOpen:
+ r=iDriver->CompleteSlowOpen((DThread*)a1,(TRequestStatus*)a2);
+ break;
+#ifdef _DEBUG_DEVCOMM
+ case RBusDevComm::EControlDebugInfo:
+ {
+ TCommDebugInfo info;
+ iDriver->DisableInterrupts();
+ info.iRxBusy = iIsReading;
+ info.iRxHeld = iOutputHeld!=0;
+ info.iRxLength = iReceiveLength;
+ info.iRxOffset = iReceiveOffset;
+ info.iRxIntCount = iDriver->iRxIntCount;
+ info.iRxErrCount = iDriver->iRxErrCount;
+ info.iRxBufCount = iRxBuf->Count();
+ info.iTxBusy = iIsWriting;
+ info.iTxHeld = iInputHeld!=KInputHeldFree;
+ info.iTxLength = iTransmitLength;
+ info.iTxOffset = iTransmitOffset;
+ info.iTxIntCount = iDriver->iTxIntCount;
+ info.iTxErrCount = iDriver->iTxErrCount;
+ info.iTxBufCount = iTxBuf->Count();
+ info.iDrainingRxBuf = iDrainingRxBuf!=0;
+ info.iFillingTxBuf = iFillingTxBuf!=0;
+ info.iRunningDfc = iRunningDfc!=0;
+ info.iDfcCount = iDfcCount;
+ info.iDfcReqSeq = iDfcReqSeq;
+ info.iDfcHandlerSeq = iDfcHandlerSeq;
+ info.iRxXon = iRxXon;
+ info.iRxXoff = iRxXoff;
+ info.iTxXon = iTxXon;
+ info.iTxXoff = iTxXoff;
+ info.iRxChars = iRxChars;
+ info.iTxChars = iTxChars;
+ info.iDoDrainSeq = iDoDrainSeq;
+ info.iTxDfcPend = (iDfcRequest&EFillTxBufferRequired)!=0;
+ info.iRxDfcPend = (iDfcRequest&EDrainRxBufferRequired)!=0;
+ iDriver->EnableInterrupts();
+ ((TDes8 *)a1)->FillZ(((TDes8 *)a1)->MaxLength());
+ len=Min(((TDes8 *)a1)->MaxLength(),sizeof(TCommDebugInfo));
+ ((TDes8 *)a1)->Copy((TUint8 *)&info,len);
+ }
+#endif
+ default:
+ r=KErrNotSupported;
+ }
+ return(r);
+ }
+
+void DChannelComm::QueueDfc(TUint aRequestMask)
+//
+// Set the flag to drain RX Buffer and queue the DFC if required.
+//
+ {
+ if (aRequestMask!=ECompleteEmergency)
+ iDriver->DisableInterrupts();
+
+ iDfcRequest |= aRequestMask;
+
+ if (!iRunningDfc)
+ {
+#ifdef _DEBUG_DEVCOMM
+ if (aRequestMask & EDrainRxBufferRequired)
+ {
+ iDfcReqSeq = iRxBuf->iRemSeqNum.Int();
+ ++iDfcCount;
+ }
+#endif
+ iRunningDfc=ETrue;
+ Kern::Add(iDfc);
+ }
+
+ if (aRequestMask!=ECompleteEmergency)
+ iDriver->EnableInterrupts();
+ }
+
+void DChannelComm::ResetDevice()
+//
+// Reset driver variables following device power down.
+//
+ {
+
+ iIsClientWriting=EFalse;
+//
+// Must leave iDfcRunning set as the Dfc may remain pending
+// This is no problem as the DfcHandler is happy if it finds
+// it has nothing to do
+//
+ iIsReading=iIsWriting=iDrainingRxBuf=iFillingTxBuf=EFalse;
+ iFlags=iDfcRequest=0;
+
+ iStatus=ENotActive;
+ }
+
+void DChannelComm::DoPowerDown()
+//
+// Called at switch off and on Closing.
+//
+ {
+
+ if (iStatus==EActive)
+ Stop(EStopPwrDown);
+ iPowerHandler->SetRequirement(0);
+ }
+
+void DChannelComm::DoEmergencyPowerDown()
+//
+// Called when the batteries run out or fall out.
+//
+ {
+
+ if (iStatus==EActive)
+ Stop(EStopEmergency);
+ QueueDfc(ECompleteEmergency);
+ }
+
+GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
+//
+// DLL entry point
+//
+ {
+
+ return KErrNone;
+ }