diff -r 000000000000 -r 83f4b4db085c toolsandutils/wintunnel/src_beech/d_comm.cpp --- /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 +#include "d_comm.h" +#include + +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; +// 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; iPutChar(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; iSetSignals(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; + }