--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolsandutils/wintunnel/src_cedar/serialpdd.cpp Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,2035 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// wins/specific/serialpdd.cpp
+// Modified serial pdd that supports IP tunneling data from the emulator to socket.
+//
+//
+
+/**
+ @file
+*/
+
+#include "winscomm.h"
+#include <nkern/nk_priv.h>
+#include <nkern/win32/nk_plat.h>
+#include <emulator.h>
+
+#include <kernel/win32/property.h>
+
+#define WIN32_LEAN_AND_MEAN
+#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
+
+#include <windows.h>
+#include <winsock2.h>
+#include <string.h>
+#include <stdlib.h>
+
+//----------------------------------------------------------------
+// logging macros. Just define WINTUN_PDD_LOGGING to enable debug trace
+// note that MSVCRTD.LIB isn't included to the serialpdd.mmp, because this **** CW does not
+// have it. Use it from MSVC package.
+
+#include <crtdbg.h>
+
+//#define WINTUN_PDD_LOGGING
+
+#ifdef WINTUN_PDD_LOGGING
+ #define _Log(a) _RPT0(_CRT_WARN,a)
+ #define _Log2(a,b) _RPT1(_CRT_WARN,a,b)
+ #define _Log3(a,b,c) _RPT2(_CRT_WARN,a,b,c)
+ #define _Log4(a,b,c,d) _RPT3(_CRT_WARN,a,b,c,d)
+
+#else
+ #define _Log(a)
+ #define _Log2(a,b)
+ #define _Log3(a,b,c)
+ #define _Log4(a,b,c,d)
+
+#endif
+
+//----------------------------------------------------------------
+
+
+#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
+
+#ifdef FAULT
+#undef FAULT
+#endif
+#define FAULT() Kern::Fault(__FILE__,__LINE__)
+
+_LIT(KComName,"COM");
+
+// needs ldd version..
+const TInt KMinimumLddMajorVersion=1;
+const TInt KMinimumLddMinorVersion=1;
+const TInt KMinimumLddBuild=1;
+
+//used for the read and write buffers in the driver.
+//large buffer reserved so any transfer to/from the client can fit into a driver buffer
+const TInt KSerialBufferMaxSize = 0x800000;
+const TInt KSerialBufferInitialSize = 0x10000;
+const TInt KSerialBufferIncrementSize = 0x1000; //granularity. must be power of 2
+
+
+const DWORD KReadOneOrMoreTimeout = MAXDWORD-1; //milliseconds
+
+
+//buffer sizes passed to NT for setting its own driver buffer sizes
+const TInt KDefaultWinNTReadBufSize = 1024;
+const TInt KDefaultWinNTWriteBufSize = 1024;
+
+static DWORD dummyLen = 0;
+
+enum TDCommWinsFault
+ {
+ EWindowsUnexpectedError,
+ EUnknownCommand,
+ EBadIOLen,
+ EEofOnSerial,
+ EWriteEarlyCompletion,
+ ELineErrorNotReported,
+ ESerialBufferTooBig,
+ EReadLength,
+ };
+
+
+class DDriverComm : public DPhysicalDevice
+ {
+public:
+ DDriverComm();
+ virtual TInt Install();
+ virtual TInt Remove();
+ virtual void GetCaps(TDes8 &aDes) const;
+ virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+ virtual TInt Validate(TInt aUnit, const TDesC8* aInfo, const TVersion &aVer);
+ };
+
+
+class DCommWins : public DComm
+ {
+public:
+ enum TDriverCommand {ESetBreak=1,EClearBreak,ETransmit,ETransmit0,
+ EGetSignals,ESetSignals,EConfigure,
+ EStop,EStopNoDrain,EStart,EDie, ETransmitCancel,
+ EReceive, EReceiveOneOrMore, EReceiveCancel,ENotifyDataAvailable,
+ ENotifySignals, EInvalidCommand};
+public:
+ DCommWins();
+ ~DCommWins();
+ virtual TInt Start();
+ virtual void Stop(TStopMode aMode);
+ virtual void Break(TBool aState);
+ virtual void Write(DThread* aThread, TAny *aTxDes, TInt aLength);
+ virtual void Read(DThread* aThread, TAny *aTxDes, TInt aLength);
+ virtual void NotifySignals(DThread* aThread, TInt aMask);
+ virtual void NotifyDataAvailable();
+ virtual TUint Signals() const;
+ virtual void SetSignals(TUint aSetMask,TUint aClearMask);
+ virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const;
+ virtual void Configure(TCommConfigV01 &aConfig);
+ virtual void Caps(TDes8 &aCaps) const;
+ virtual void CheckConfig(TCommConfigV01& aConfig);
+ virtual TDfcQue* DfcQ(TInt aUnit);
+
+ inline void CheckTxBuffer();
+ inline TBool Transmitting();
+ virtual TInt RxCount();
+ virtual void ResetBuffers(TBool);
+ virtual TInt SetRxBufferSize(TInt aSize);
+ virtual TInt RxBufferSize();
+ virtual TDes8* RxBuffer();
+ virtual void DoConfigure();
+ virtual TBool AreAnyPending();
+ virtual void ReadCancel();
+ virtual void WriteCancel();
+ virtual void SignalChangeCancel();
+ TInt DoCreate(TInt aUnit,const TDesC8 *aInfo);
+ void WaitForEvent();
+ void DriverCommand(TDriverCommand aCommand);
+ void DoWriteComplete(TInt aErr);
+ void DoReadComplete(TInt aErr, TInt aBytes);
+ void DoSignalCompletion(TInt aError, TUint changed, TUint aValues);
+ void DoDataAvailableCompletion();
+ void RunCommThread(TDriverCommand aCommand);
+ inline void SignalDriverThread();
+
+ TInt QueSocketRead();
+
+ /** @return ETrue if we use socket instead of a real COM port */
+ TBool inline UseSocket(void) const
+ {return (iSocket != INVALID_SOCKET) && (iSocket != NULL); }
+
+private:
+ void ReleaseBuffers();
+ void ReSizeBuffer(TUint8*& aBuf, TInt& iBufLen, TPtr8& aDes, const TInt aNewLen);
+ TBool IsATerminator(TText8 aChar);
+ void CompleteRead(TInt aLength);
+ void DataAvailableNotificationCancel();
+
+
+private:
+ TInt iWritePending;
+ TInt iReadPending;
+ TBool iStopping;
+ TBool iRunning;
+ TDriverCommand iCommand;
+ TCommConfigV01 *iConfig;
+ TUint iSignals;
+ TUint iFailSignals;
+ TUint iSavedSignals;
+ TBool iLineFail;
+ TBool iRXLineFail;
+ TBool iTXLineFail;
+
+ TUint8 * iInBufPtr; //input buffer used by driver.
+ TInt iInBufLength;
+ TPtr8 iInDes;
+
+ TInt iReadSoFar;
+ TBool iTerminatedRead; //true if we are reading with 1 or more terminating characters
+
+ TUint8 * iOutBufPtr;
+ TInt iOutBufLength;
+ TPtr8 iOutDes;
+
+ TInt iRxBufferSize; //size of receivebuffer passed to windows & set by calls to SetReceiveBufferSize
+ //used to determine xon and xoff levels
+ TUint iSignalsRequested; //mask of signals we are waiting for
+ TUint iSignalsWanted; //mask we are asked to check
+ TBool iDataAvailableNotification;
+ HANDLE iThread;
+ HANDLE iCommThreadSem;
+ HANDLE iDriverThreadSem;
+ HANDLE iCommPort;
+ DWORD iThreadID;
+ DWORD iSignalStatus;
+ OVERLAPPED iReadOverLapped;
+ OVERLAPPED iWriteOverLapped;
+ OVERLAPPED iSignalOverLapped;
+
+ TInt iClientReadLength; //how much data the client has requested in a read
+
+ //-- win tunnel specific members
+ SOCKET iSocket; //< socket for serial port simulation
+ char iOptions[151]; //< contains a string with mapping serial port numbers to the IPs
+ TBool iReadCancel; //< flag, used to indicate that the read was cancelled during socket read
+
+ };
+
+void Panic(TDCommWinsFault aFault)
+//
+// Panic the driver
+//
+ {
+ Kern::PanicCurrentThread(_L("DCommWins"), aFault);
+ }
+
+
+TUint commThread(DCommWins *comm)
+//
+// Comm thread entry point
+//
+ {
+
+ comm->WaitForEvent();
+ return 0;
+ }
+
+VOID WINAPI WriteCompletion(DCommWins *aDrv, DWORD aErr,DWORD /*numBytes*/)
+ {
+
+ aDrv->DoWriteComplete(aErr);
+ }
+
+
+VOID WINAPI ReadCompletion(DCommWins *aDrv, DWORD aErr,DWORD numBytes)
+ {
+
+ aDrv->DoReadComplete(aErr, numBytes);
+ }
+
+VOID WINAPI SignalCompletion(DCommWins *aDrv, TInt aError, TUint aChanged, TUint aValues)
+ {
+ aDrv->DoSignalCompletion(aError, aChanged, aValues);
+ }
+
+VOID WINAPI DataAvailableCompletion(DCommWins *aDrv)
+ {
+ aDrv->DoDataAvailableCompletion();
+ }
+
+
+
+BOOL WINAPI EscapeCommFunctionP(HANDLE hFile,DWORD dwFunc, TBool bUseSocket)
+ {
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ if(bUseSocket)
+ {
+ res = FALSE;//, not supported... EscapeCommFunction(hFile,dwFunc);
+ }
+ else
+ do
+ {
+ ClearCommError(hFile, &err, &s);
+ res = EscapeCommFunction(hFile,dwFunc);
+ if(!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ return res;
+ }
+
+
+BOOL WINAPI GetCommModemStatusP(HANDLE hFile,LPDWORD lpModemStat, TBool bUseSocket)
+{
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ if(bUseSocket)
+ {
+ res = FALSE;//, not supported... GetCommModemStatus(hFile,lpModemStat);
+ }
+ else
+ do
+ {
+ ClearCommError(hFile, &err, &s);
+ res = GetCommModemStatus(hFile,lpModemStat);
+ if(!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ return(res);
+}
+
+
+BOOL WINAPI GetCommStateP(HANDLE hFile,LPDCB lpDCB, TBool bUseSocket)
+{
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ if(bUseSocket)
+ {
+ res = FALSE;//, not supported... GetCommState(hFile,lpDCB);
+ }
+ else
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ res = GetCommState(hFile,lpDCB);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ return(res);
+}
+
+BOOL WINAPI SetCommStateP(HANDLE hFile,LPDCB lpDCB, TBool bUseSocket)
+ {
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ if(bUseSocket)
+ {
+ res = FALSE;//, not supported... SetCommState(hFile, lpDCB);
+ }
+ else
+ do
+ {
+ ClearCommError(hFile, &err, &s);
+ res = SetCommState(hFile, lpDCB);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ return(res);
+ }
+
+BOOL WINAPI SetCommMaskP(HANDLE hFile,DWORD dwEvtMask, TBool bUseSocket)
+{
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ if(bUseSocket)
+ {
+ res = FALSE;//, not supported... SetCommMask(hFile, dwEvtMask);
+ }
+ else
+ do
+ {
+ ClearCommError(hFile, &err, &s);
+ res = SetCommMask(hFile, dwEvtMask);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ return(res);
+}
+
+BOOL WINAPI WriteFileP(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped, TBool bUseSocket)
+ {
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ if(bUseSocket)
+ {//-- tunnel data to the socket
+ WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
+ }
+ else
+ do
+ {//-- normal operation with serial port
+ ClearCommError(hFile, &err, &s);
+ res = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ return(res);
+ }
+
+BOOL WINAPI ReadFileP(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped, TBool bUseSocket)
+ {
+ DWORD err;
+ DWORD lastError = 0;
+ BOOL res;
+ COMSTAT s;
+
+ _Log2("#ReadFileP()#1 to read: %d bytes \n", nNumberOfBytesToRead);
+
+ if(bUseSocket)
+ {//-- tunnel data to the socket
+ ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
+ }
+
+ else
+ do
+ {//-- normal operation with serial port
+ ClearCommError(hFile, &err, &s);
+ res = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+ _Log2("#ReadFileP()#2 read: %d bytes \n", *lpNumberOfBytesRead);
+
+ return(res);
+ }
+
+
+
+
+DDriverComm::DDriverComm()
+ {
+#if defined (__COM_ONE_ONLY__)
+ iUnitsMask=0x1; // Support units 0
+#elif defined (__COM_TWO_ONLY__)
+ iUnitsMask=0x2; // Support units 1
+#else
+ iUnitsMask=0x3ff; // Support units 0 to 9
+#endif
+
+ iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+ }
+
+TInt DDriverComm::Install()
+ {
+#if defined (__COM_ONE_ONLY__)
+ TPtrC buf=_L("Comm.Wins1");
+ return(SetName(&buf));
+#elif defined (__COM_TWO_ONLY__)
+ TPtrC buf=_L("Comm.Wins2");
+ return(SetName(&buf));
+#else
+ TPtrC buf=_L("Comm.Wins");
+ return(SetName(&buf));
+#endif
+ }
+
+TInt DDriverComm::Remove()
+ {
+ return(KErrNone);
+ }
+
+
+TInt DDriverComm::Validate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+//
+// Validate the requested configuration
+//
+ {
+ if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
+ return KErrNotSupported;
+#if defined (__COM_ONE_ONLY__)
+ if (aUnit!=0)
+ return KErrNotSupported;
+#elif defined (__COM_TWO_ONLY__)
+ if (aUnit!=1)
+ return KErrNotSupported;
+#endif
+ // leave Unit check to CreateFile
+ return KErrNone;
+ }
+
+
+void GetWinsCommsCaps(TDes8 &aCaps)
+ {
+
+ TCommCaps2 capsBuf;
+ TCommCapsV02 &c=capsBuf();
+//
+// All rates except 50,2000, 3600 and special
+//
+ c.iRate=KCapsBps75|KCapsBps110|KCapsBps134|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps1800|KCapsBps2400|KCapsBps4800|KCapsBps7200|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200;
+
+ c.iDataBits=0xf; // All data sizes
+ c.iStopBits=0x3; // 1 and 2 stop bits
+ c.iParity=0x7; // None, Even and Odd
+ c.iHandshake = 0x3BF; //all except KConfigObeyDCD
+ c.iSignals=0x3f; // All signals
+ c.iSIR=0;//No Ir
+ c.iNotificationCaps=KNotifySignalsChangeSupported|KNotifyDataAvailableSupported;
+ c.iRoleCaps=0;
+ c.iFlowControlCaps=0;
+ aCaps.FillZ(aCaps.MaxLength());
+ aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
+ }
+
+void DDriverComm::GetCaps(TDes8 &aDes) const
+ {
+
+ GetWinsCommsCaps(aDes);
+ }
+TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit,const TDesC8* aInfo,const TVersion& aVer)
+ {
+
+ if (!Kern::QueryVersionSupported(iVersion,aVer))
+ return KErrNotSupported;
+
+ DCommWins *pD= new DCommWins;
+ if (!pD) return KErrNoMemory;
+
+ TInt ret=pD->DoCreate(aUnit,aInfo);
+
+ if (ret!=KErrNone)
+ {
+ delete pD;
+ return ret;
+ }
+
+ aChannel = pD;
+
+ return KErrNone;
+ }
+
+/**
+ Associate event with our socket
+*/
+TInt DCommWins::QueSocketRead()
+{
+ _Log("# DCommWins::QueSocketRead()\n");
+ if(WSAEventSelect(iSocket, iReadOverLapped.hEvent, FD_READ | FD_CLOSE))
+ {// Some error?!?
+ DWORD res = WSAGetLastError();
+ return res;
+ }
+
+ return KErrNone;
+
+}
+
+void DCommWins::DoWriteComplete(TInt aErr)
+ {
+ iWritePending = 0;
+ StartOfInterrupt();
+ iLdd->iTxError = aErr;
+ iLdd->iTxCompleteDfc.Add();
+ EndOfInterrupt();
+ }
+
+
+
+void DCommWins::DoSignalCompletion(TInt aError, TUint aChanged, TUint aValues)
+ {
+
+ //aValues contains the signal values. EPOC constants
+ //aChanged contains the signals which have changed
+ //we return the signal values
+ TUint res = aValues & iSignalsWanted;
+ res |= (aChanged << 12);
+
+ iLdd->iSignalResult = res;
+ iLdd->iSignalError = aError;
+ StartOfInterrupt();
+ iLdd->iSigNotifyDfc.Add();
+ EndOfInterrupt();
+ }
+
+void DCommWins::DoDataAvailableCompletion()
+ {
+ StartOfInterrupt();
+ iLdd->iRxDataAvailableDfc.Add();
+ EndOfInterrupt();
+ }
+
+
+
+void DCommWins::CompleteRead(TInt aLength)
+ {
+
+ _Log2("# DCommWins::CompleteRead(), len=%d\n", aLength);
+
+ iReadPending = 0;
+ iInDes.SetLength(aLength);
+ StartOfInterrupt();
+ iLdd->iRxCompleteDfc.Add();
+ EndOfInterrupt();
+ }
+
+
+
+void DCommWins::DoReadComplete(TInt aErr, TInt aBytes)
+ {
+ _Log3("# DCommWins::DoReadComplete(), err=%d, bytes=%d\n", aErr, aBytes);
+
+ iLdd->iRxError = aErr;
+ //write back the length and the data
+ //process for any terminating characters.
+ //win32 only does binary reads and ignores the eofchar, so terminated reads
+ //require reading one char at a time
+ if (iTerminatedRead && !aErr)
+ {
+ __NK_ASSERT_ALWAYS(aBytes <= 1);
+ if (aBytes == 0)
+ {
+ // not sure why we get this somtimes, but handle it anyway : read another character
+ ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped, UseSocket());
+ }
+ else if (++iReadSoFar == iClientReadLength) //see if we have read enough characters into the buffer
+ {
+ //got them all so complete it
+ CompleteRead(iReadSoFar);
+ }
+ else if (IsATerminator(iInBufPtr[iReadSoFar-1])) //see if the char just read was the terminator
+ {
+ //it's a terminated read and we've found one of the terminbators
+ CompleteRead(iReadSoFar);
+ }
+ else if (iReadPending == EReceive)
+ {
+ //read another character
+ ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped, UseSocket());
+ }
+ else
+ {
+ //it's a receive 1 or more with terminators, we've got 1 so that'll do
+ CompleteRead(iReadSoFar);
+ }
+ }
+ else
+ {
+ CompleteRead(aBytes);
+ }
+ }
+
+
+
+
+void DCommWins::RunCommThread(TDriverCommand aCommand)
+//
+// Wake up the comms thread
+//
+ {
+ _Log2("# DCommWins::RunCommThread, command=%d\n", aCommand);
+
+ __ASSERT_DEBUG(aCommand!=EInvalidCommand,Panic(EUnknownCommand));
+ iCommand=aCommand;
+//
+// Are we about to go re-entrant?
+//
+ if(GetCurrentThreadId()==iThreadID)
+ {
+ _Log("# DCommWins::RunCommThread() DriverCommand #1\n");
+ DriverCommand(aCommand);
+
+ _Log("#~ DCommWins::RunCommThread() WaitForSingleObject #1\n");
+ WaitForSingleObject(iDriverThreadSem,INFINITE);
+ }
+ else
+ {
+ Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
+
+ _Log("# DCommWins::RunCommThread() Release iCommThreadSem\n");
+ if (ReleaseSemaphore(iCommThreadSem,1,NULL)==FALSE)
+ {
+ DWORD ret=GetLastError();
+ ret=ret;
+ Panic(EWindowsUnexpectedError);
+ }
+
+ _Log("#~ DCommWins::RunCommThread() WaitForSingleObject #2\n");
+ WaitForSingleObject(iDriverThreadSem,INFINITE);
+ _Log("# DCommWins::RunCommThread() checkpoint #2\n");
+ }
+ }
+
+inline void DCommWins::SignalDriverThread()
+//
+// Wake up the comms thread
+//
+ {
+ _Log("# DCommWins::SignalDriverThread(), release iDriverThreadSem\n");
+
+ Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
+ if (ReleaseSemaphore(iDriverThreadSem,1,NULL)==FALSE)
+ {
+ DWORD ret=GetLastError();
+ ret=ret;
+ Panic(EWindowsUnexpectedError);
+ }
+ }
+
+
+
+//
+#pragma warning( disable : 4705 ) // statement has no effect
+DCommWins::DCommWins() : iOutDes(0,0), iInDes(0,0), iRxBufferSize(KDefaultWinNTReadBufSize), iSignalsRequested(0)
+ {
+ __DECLARE_NAME(_S("DCommWins"));
+
+ _Log("# ------------------------------------------------\n");
+ _Log("# DCommWins::DCommWins()\n");
+
+ iSocket = INVALID_SOCKET;
+ }
+#pragma warning( default : 4705 )
+
+
+//-----------------------------------------------------------------------------------------------
+
+/**
+* Create the comms driver.
+* @param aUnit serial porn number to work with (starts with 0)
+*/
+
+
+//-----------------------------------------------------------------------------------------------
+TInt DCommWins::DoCreate(TInt aUnit,const TDesC8 * /*aInfo*/)
+ {
+
+ _Log("# DCommWins::DoCreate()\n");
+
+#if defined (__COM_ONE_ONLY__)
+ if (aUnit!=0)
+ return KErrNotSupported;
+#elif defined (__COM_TWO_ONLY__)
+ if (aUnit!=1)
+ return KErrNotSupported;
+#endif
+
+ //-- obtain and parse a string with mapping serial ports to IP addresses
+ //-- the string shall look like: WIN_TUNNEL=0,10.35.2.53,110;4,10.35.2.59,110;5,10.35.2.50,110;6,10.35.2.50,443;7,10.35.2.53,443
+ TInt foundPort = 0;
+ TInt supposedPort= -1;
+ char* hostname = iOptions;
+ TInt16 portNumber = 0;
+
+ const char * property = Property::GetString("WIN_TUNNEL");
+
+ if(property)
+ {
+ if((strlen(property) < 5) || (strlen(property) > 150))
+ FAULT(); //-- illegal parameter string length
+
+ strcpy(iOptions, property);
+ char* pchBeg = iOptions;
+
+ while(!foundPort && pchBeg)
+ {
+ char* pchEnd;
+
+ supposedPort = strtol(pchBeg, &pchEnd, 10);
+
+ if(aUnit == supposedPort)
+ {//-- found a com port number, extract IP address and port for the socket
+ if(*pchEnd++ != ',')
+ FAULT();
+
+ hostname = pchBeg = pchEnd;
+ pchEnd = strchr(pchBeg, ',');
+ pchBeg = pchEnd + 1;
+ *pchEnd = '\0';
+
+ portNumber = (TInt16)strtol(pchBeg, &pchEnd, 10);
+
+ foundPort = 1;
+ }
+ else
+ {
+ pchBeg = strchr(pchBeg, ';');
+
+ if(pchBeg)
+ pchBeg ++;
+ }
+ }
+ }//if(property)
+
+
+ //-----------------------------------------
+
+ //create the buffers.
+ //the buffers need to be as big as the client will ever use. 8mb reserved, but commit less
+ iInBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
+ if (!iInBufPtr)
+ return(Emulator::LastError());
+
+ //commit the first bit of the buffer
+ if (!VirtualAlloc(iInBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
+ return(Emulator::LastError());
+
+ iInBufLength = KSerialBufferInitialSize;
+ iInDes.Set(iInBufPtr, 0, iInBufLength);
+
+ //reserve address space for the output buffer
+ iOutBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
+ if (!iOutBufPtr)
+ return(Emulator::LastError());
+
+ //commit a smaller region of it
+ if (!VirtualAlloc(iOutBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
+ return(Emulator::LastError());
+
+ iOutBufLength = KSerialBufferInitialSize;
+ iOutDes.Set(iOutBufPtr, 0, iOutBufLength);
+
+ //-----------------------------------------
+
+
+ if(aUnit == supposedPort)
+ {//-- a serial port number is found in the parameter string.
+ //-- create and connect socket.
+
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ wVersionRequested = MAKEWORD(2, 0);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0)
+ return(Emulator::LastError());
+
+
+ //-- create a socket
+ iSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
+
+ _Log3("# DCommWins: created socket id: %d, port emulation: %d\n", iSocket, supposedPort);
+
+ if(iSocket == INVALID_SOCKET)
+ {
+ err = WSAGetLastError();
+ return(Emulator::LastError());
+ }
+
+ sockaddr_in sin;
+ u_long nRemoteAddr = inet_addr(hostname);
+
+ if (nRemoteAddr != INADDR_NONE)
+ {
+ sin.sin_addr.s_addr = nRemoteAddr;
+ }
+ else
+ {
+ struct hostent FAR * hostaddr = gethostbyname (hostname);
+ if(hostaddr == NULL)
+ {
+ err = WSAGetLastError();
+ return(Emulator::LastError());
+ }
+ sin.sin_addr.s_addr = *((u_long*)hostaddr->h_addr_list[0]);
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(portNumber);
+
+ //-- connect to the server
+ err = WSAConnect(iSocket, (sockaddr*)&sin, sizeof(sin), 0, 0, 0, 0);
+ if(err)
+ {
+ err = WSAGetLastError();
+ return(Emulator::LastError());
+ }
+
+ _Log("# DCommWins: socket connected. \n");
+
+ iCommPort = (void*)iSocket;
+
+ }
+
+ //-----------------------------------------
+
+ if( !UseSocket() )
+ {
+ _Log2("# DCommWins: Using serial port# %d \n",aUnit);
+
+ //-- Open a true serial port
+ TBuf8<0x10> n;
+ n.Append(KComName);
+ n.AppendNum(aUnit+1);
+ n.Append('\0');
+
+ iCommPort=CreateFileA((LPCSTR)n.Ptr(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
+ if (iCommPort==INVALID_HANDLE_VALUE)
+ {
+ // Reused code from Emulator::LastError() rather than adding an extra case
+ // to Emulator::LastError() because mapping KErrNotSupported to the returned
+ // FILE_NOT_FOUND is non-intuitive and special to this case only
+ DWORD winErr=GetLastError();
+ switch (winErr)
+ {
+ case ERROR_INVALID_USER_BUFFER:
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_INSUFFICIENT_BUFFER:
+ return(KErrNoMemory);
+ case ERROR_ACCESS_DENIED:
+ return(KErrAccessDenied);
+ case ERROR_FILE_NOT_FOUND: // Reflects value returned by
+ return(KErrNotSupported); // corresponding MARM Pdd
+ case ERROR_NOT_SUPPORTED:
+ return(KErrNotSupported);
+ default:
+ return(KErrGeneral);
+ }
+ }
+
+
+ DCB dcb;
+ //set the dcb size
+ dcb.DCBlength = sizeof(dcb);
+ if (!GetCommStateP(iCommPort,&dcb, UseSocket()))
+ return(Emulator::LastError());
+
+ EscapeCommFunctionP(iCommPort,0, UseSocket());
+
+ if (!SetCommMaskP(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR|EV_RING, UseSocket()))
+ return(Emulator::LastError());
+
+ if(!SetupComm(iCommPort,KDefaultWinNTReadBufSize,KDefaultWinNTWriteBufSize))
+ return(Emulator::LastError());
+
+ }//if( !UseSocket() )
+
+ _Log("# DCommWins: creating semaphores. \n");
+
+ //--- create thread semaphores
+ if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+ return(Emulator::LastError());
+
+ if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+ return(Emulator::LastError());
+
+ //-----------------------------------------
+
+ if( !UseSocket() )
+ {// The serial port seems to open with the error condition set
+ DWORD err,res;
+ COMSTAT s;
+ if (ClearCommError(iCommPort,&err,&s)==FALSE)
+ res=GetLastError();
+ }
+
+ _Log("# DCommWins: creating comm thread. \n");
+
+ iReadCancel = EFalse;
+
+ if ((iThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)commThread,(void *)this, FALSE))==NULL)
+ return(Emulator::LastError());
+
+ SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
+
+ _Log("# DCommWins::DoCreate() exit\n");
+ return(KErrNone);
+ }
+
+
+
+void DCommWins::ReleaseBuffers()
+ {
+ if (iInBufPtr)
+ {
+ //decommit the buffer
+ VirtualFree(iInBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
+ //and release the region
+ VirtualFree(iInBufPtr, NULL, MEM_RELEASE);
+ iInBufPtr = NULL;
+ }
+ if (iOutBufPtr)
+ {
+ VirtualFree(iOutBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
+ VirtualFree(iOutBufPtr, NULL, MEM_RELEASE);
+ iOutBufPtr = NULL;
+ }
+ }
+
+
+DCommWins::~DCommWins()
+ {
+ _Log("# DCommWins::~DCommWins()\n");
+ if (iThread)
+ {
+ if (! iRunning)
+ {
+ __ASSERT_ALWAYS(
+ ResumeThread(iThread) != 0xffffffff,
+ Panic(EWindowsUnexpectedError));
+ }
+
+ iRunning=ETrue;
+ RunCommThread(EDie);
+ }
+
+ if(UseSocket())
+ {
+ closesocket(iSocket);
+ WSACleanup();
+ iCommPort = (HANDLE) NULL;
+ iSocket = NULL;
+ }
+
+ if (iCommPort)
+ {
+ CloseHandle(iCommPort);
+ }
+
+ if (iDriverThreadSem)
+ CloseHandle(iDriverThreadSem);
+
+ if (iCommThreadSem)
+ CloseHandle(iCommThreadSem);
+
+ if (iReadOverLapped.hEvent)
+ CloseHandle(iReadOverLapped.hEvent);
+
+ if (iWriteOverLapped.hEvent)
+ CloseHandle(iWriteOverLapped.hEvent);
+
+ if (iSignalOverLapped.hEvent)
+ CloseHandle(iSignalOverLapped.hEvent);
+
+ if (iThread)
+ CloseHandle(iThread);
+
+ //free up the memory
+ ReleaseBuffers();
+
+ _Log("# DCommWins::~DCommWins() exit\n");
+
+ }
+
+TInt DCommWins::Start()
+ {
+
+ __ASSERT_ALWAYS(ResumeThread(iThread)!=0xffffffff,Panic(EWindowsUnexpectedError));
+ iRunning=ETrue;
+ RunCommThread(EStart);
+ return(KErrNone);
+ }
+
+void DCommWins::Stop(TStopMode aMode)
+ {
+
+ RunCommThread((aMode==EStopEmergency) ? EStopNoDrain : EStop);
+ SuspendThread(iThread);
+ iRunning=EFalse;
+ }
+
+void DCommWins::Break(TBool aState)
+//
+// Assert a break signal
+//
+ {
+
+ if (aState)
+ RunCommThread(ESetBreak);
+ else
+ RunCommThread(EClearBreak);
+ }
+
+
+
+TInt DCommWins::RxCount()
+ {
+ DWORD err =0;
+ COMSTAT stat;
+ if (ClearCommError(iCommPort,&err, &stat))
+ return stat.cbInQue;
+ else
+ return Emulator::LastError();
+ }
+
+
+void DCommWins::ResetBuffers(TBool aTx)
+ {
+ PurgeComm(iCommPort, PURGE_RXCLEAR | (aTx ? PURGE_TXCLEAR : 0));
+ }
+
+
+TBool DCommWins::AreAnyPending()
+ {
+ return (iReadPending != 0) || (iWritePending != 0);
+ }
+
+
+void DCommWins::WriteCancel()
+ {
+ DriverCommand(ETransmitCancel);
+ }
+
+
+void DCommWins::ReadCancel()
+ {
+ DriverCommand(EReceiveCancel);
+ }
+
+void DCommWins::SignalChangeCancel()
+ {
+ if (iSignalsRequested)
+ {
+ iSignalsRequested = 0;
+ }
+
+ }
+
+void DCommWins::DataAvailableNotificationCancel()
+ {
+ if (iDataAvailableNotification)
+ {
+ iDataAvailableNotification = EFalse;
+ iLdd->iRxDAError = KErrCancel;
+ iLdd->iRxDataAvailableDfc.Enque();
+ }
+ }
+
+TDes8* DCommWins::RxBuffer()
+ {
+ return &iInDes;
+ }
+
+TInt DCommWins::SetRxBufferSize(TInt aSize)
+ {
+ aSize += aSize&1; //round up to multiple of 2 bytes as windows complains if odd
+ TInt ret = SetupComm(iCommPort, aSize, KDefaultWinNTWriteBufSize);
+ if (ret)
+ {
+ iRxBufferSize = aSize;
+
+ DCB dcb = {0};
+ dcb.DCBlength = sizeof(dcb);
+
+ if (!GetCommStateP(iCommPort,&dcb, UseSocket()))
+ return Emulator::LastError();
+
+ //use rx buffer size to configure xon/xoff limits
+ dcb.XoffLim = (WORD)(iRxBufferSize / 4); //25%
+ if (iConfig->iParityError & KConfigXonXoffDebug)
+ dcb.XonLim = (WORD)((iRxBufferSize / 2) -5); //50%-5
+ else
+ dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3); //75%
+
+ if (!SetCommStateP(iCommPort,&dcb, UseSocket()))
+ return Emulator::LastError();
+
+ return KErrNone;
+ }
+ return Emulator::LastError();
+ }
+
+
+TInt DCommWins::RxBufferSize()
+ {
+ return iRxBufferSize;
+ }
+
+
+TBool DCommWins::IsATerminator(TText8 aChar)
+ {
+ TInt x;
+ for (x=0; x < iConfig->iTerminatorCount; x++)
+ if (aChar == iConfig->iTerminator[x])
+ return ETrue;
+ return EFalse;
+ }
+
+
+void DCommWins::ReSizeBuffer(TUint8*& aBuf, TInt& aBufLen, TPtr8& aDes, const TInt aNewLen)
+ {
+
+ if (aNewLen > KSerialBufferMaxSize)
+ Panic(ESerialBufferTooBig);
+
+ aBufLen = ((aNewLen + KSerialBufferIncrementSize-1) / KSerialBufferIncrementSize) * KSerialBufferIncrementSize;
+
+ if (aBufLen > KSerialBufferMaxSize)
+ aBufLen = KSerialBufferMaxSize;
+
+ if (!VirtualAlloc(aBuf, aBufLen, MEM_COMMIT,PAGE_READWRITE))
+ {
+ ReleaseBuffers();
+ Panic(ESerialBufferTooBig);
+ }
+ aDes.Set(aBuf, 0, aBufLen);
+ }
+
+
+void DCommWins::Write(DThread* aThread, TAny* aSrc, TInt aLength)
+
+ {
+ if (aLength==0)
+ {
+ RunCommThread(ETransmit0);
+ }
+ else
+ {
+ if (aLength > iOutBufLength)
+ ReSizeBuffer(iOutBufPtr, iOutBufLength, iOutDes, aLength);
+
+ //copy the data from the client
+ Kern::ThreadDesRead(aThread, aSrc, iOutDes, 0,0);
+ iOutDes.SetLength(aLength);
+ //tell the comms thread to write the data
+ RunCommThread(ETransmit);
+ }
+ }
+
+void DCommWins::NotifySignals(DThread* /*aThread*/, TInt aMask)
+ {
+ iSignalsWanted = aMask;
+ RunCommThread(ENotifySignals);
+ }
+
+
+void DCommWins::NotifyDataAvailable()
+ {
+ RunCommThread(ENotifyDataAvailable);
+ }
+
+
+void DCommWins::Read(DThread* /*aThread*/, TAny* /*aDest*/, TInt aLength)
+
+ {
+ _Log2("# DCommWins::Read, len=%d\n", aLength);
+
+ TDriverCommand command;
+
+ if (aLength < 0)
+ {
+ iClientReadLength = Abs(aLength);
+ command = EReceiveOneOrMore;
+ }
+ else
+ {
+ iClientReadLength = aLength;
+ command = EReceive;
+ }
+
+ if (iClientReadLength > iInBufLength)
+ ReSizeBuffer(iInBufPtr, iInBufLength, iInDes, iClientReadLength);
+
+ //tell the comms thread to read the data
+ RunCommThread(command);
+ }
+
+
+
+
+
+TUint DCommWins::Signals() const
+{
+ if(UseSocket())
+ return MS_CTS_ON|MS_DSR_ON|KSignalCTS|KSignalDSR;
+
+ ULONG signals=0;
+ GetCommModemStatusP(iCommPort,&signals, UseSocket());
+ TUint status=0;
+ if (signals&MS_CTS_ON)
+ status|=KSignalCTS;
+ if (signals&MS_DSR_ON)
+ status|=KSignalDSR;
+ if (signals&MS_RING_ON)
+ status|=KSignalRNG;
+ if (signals&MS_RLSD_ON)
+ status|=KSignalDCD;
+ return(status|iSignals);
+}
+
+
+void DCommWins::SetSignals(TUint aSetMask,TUint aClearMask)
+ {
+ if (aSetMask&KSignalRTS)
+ {
+ iSignals|=KSignalRTS;
+ EscapeCommFunctionP(iCommPort,SETRTS, UseSocket());
+ }
+ if (aSetMask&KSignalDTR)
+ {
+ iSignals|=KSignalDTR;
+ EscapeCommFunctionP(iCommPort,SETDTR, UseSocket());
+ }
+ if (aClearMask&KSignalRTS)
+ {
+ iSignals&=(~KSignalRTS);
+ EscapeCommFunctionP(iCommPort,CLRRTS, UseSocket());
+ }
+ if (aClearMask&KSignalDTR)
+ {
+ iSignals&=(~KSignalDTR);
+ EscapeCommFunctionP(iCommPort,CLRDTR, UseSocket());
+ }
+ }
+
+
+
+void DCommWins::CheckConfig(TCommConfigV01& /*aConfig*/)
+ {
+ // Do nothing
+ }
+
+
+
+void DCommWins::Configure(TCommConfigV01 &aConfig)
+//
+// Ask comm thread to set up the serial port
+//
+ {
+
+ iConfig=&aConfig;
+ if (iRunning)
+ {
+ RunCommThread(EConfigure);
+ }
+ else
+ {
+// iCommand=EConfigure;
+ DoConfigure();
+ }
+ }
+
+void DCommWins::DoConfigure()
+//
+// Set up the serial port
+//
+ {
+
+ if(UseSocket())
+ return; // nothing to configure
+
+ DCB dcb = {0};
+ //set the dcb size
+ dcb.DCBlength = sizeof(dcb);
+ if (!GetCommStateP(iCommPort,&dcb, UseSocket()))
+ return;
+
+
+ //stop if an error happens
+ dcb.fAbortOnError = TRUE;
+
+ //baud rate
+ switch (iConfig->iRate)
+ {
+ case EBps75:
+ dcb.BaudRate=75;
+ break;
+ case EBps110:
+ dcb.BaudRate=110;
+ break;
+ case EBps134:
+ dcb.BaudRate=134;
+ break;
+ case EBps150:
+ dcb.BaudRate=150;
+ break;
+ case EBps300:
+ dcb.BaudRate=300;
+ break;
+ case EBps600:
+ dcb.BaudRate=600;
+ break;
+ case EBps1200:
+ dcb.BaudRate=1200;
+ break;
+ case EBps1800:
+ dcb.BaudRate=1800;
+ break;
+ case EBps2400:
+ dcb.BaudRate=2400;
+ break;
+ case EBps4800:
+ dcb.BaudRate=4800;
+ break;
+ case EBps7200:
+ dcb.BaudRate=7200;
+ break;
+ case EBps9600:
+ dcb.BaudRate=9600;
+ break;
+ case EBps19200:
+ dcb.BaudRate=19200;
+ break;
+ case EBps38400:
+ dcb.BaudRate=38400;
+ break;
+ case EBps57600:
+ dcb.BaudRate=57600;
+ break;
+ case EBps115200:
+ dcb.BaudRate=115200;
+ break;
+ }
+
+ switch (iConfig->iParity)
+ {
+ case EParityNone:
+ dcb.Parity=NOPARITY;
+ dcb.fParity = FALSE;
+ break;
+ case EParityEven:
+ dcb.Parity=EVENPARITY;
+ dcb.fParity = TRUE;
+ break;
+ case EParityOdd:
+ dcb.Parity=ODDPARITY;
+ dcb.fParity = TRUE;
+ break;
+ case EParityMark:
+ dcb.Parity = MARKPARITY;
+ dcb.fParity = TRUE;
+ break;
+ case EParitySpace:
+ dcb.Parity = SPACEPARITY;
+ dcb.fParity = TRUE;
+ break;
+ }
+
+ switch (iConfig->iParityError)
+ {
+ case KConfigParityErrorFail:
+ dcb.fErrorChar = FALSE;
+ break;
+
+ case KConfigParityErrorIgnore:
+ dcb.fErrorChar = FALSE;
+ dcb.fAbortOnError = FALSE;
+ break;
+
+ case KConfigParityErrorReplaceChar:
+ dcb.fErrorChar = TRUE;
+ dcb.ErrorChar = iConfig->iParityErrorChar;
+ break;
+ }
+
+
+ TUint& hs = iConfig->iHandshake;
+
+
+ //SOFTWARE FLOW CONTROL
+ dcb.fInX = (hs & KConfigObeyXoff) ? TRUE : FALSE;
+ dcb.fOutX = (hs & KConfigSendXoff) ? TRUE : FALSE;
+
+ dcb.XonChar = iConfig->iXonChar;
+ dcb.XoffChar = iConfig->iXoffChar;
+ dcb.ErrorChar = iConfig->iParityErrorChar;
+
+ //use rx buffer size to configure xon/xoff limits
+ dcb.XoffLim = (WORD)(iRxBufferSize / 4); //25%
+ if (iConfig->iParityError & KConfigXonXoffDebug)
+ dcb.XonLim = (WORD)((iRxBufferSize / 2) -5); //50%-5
+ else
+ dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3); //75%
+
+
+
+ //OUTPUT HARDWARE FLOW CONTROL
+ //set out DSR control to be off
+ dcb.fOutxDsrFlow = FALSE;
+ dcb.fOutxCtsFlow = (hs & KConfigObeyCTS) ? TRUE : FALSE;
+ dcb.fDsrSensitivity = (hs & KConfigObeyDSR) ? TRUE : FALSE;
+
+
+ if (hs & KConfigObeyDCD)
+ {
+ }
+
+
+ //INPUT HARDWARE FLOW CONTROL
+ dcb.fRtsControl = (hs & KConfigFreeRTS) ? RTS_CONTROL_DISABLE : RTS_CONTROL_HANDSHAKE;
+ dcb.fDtrControl = (hs & KConfigFreeDTR) ? DTR_CONTROL_DISABLE : DTR_CONTROL_ENABLE;
+
+
+ //complete with KErrCommsLineFail if these are set and the line goes low
+ iFailSignals = 0;
+ if (hs & KConfigFailDSR)
+ iFailSignals |= KSignalDSR;
+
+ if (hs & KConfigFailCTS)
+ iFailSignals |= KSignalCTS;
+
+ if (hs & KConfigFailDCD)
+ iFailSignals |= KSignalDCD;
+
+
+ iTerminatedRead = iConfig->iTerminatorCount > 0;
+
+ switch(iConfig->iDataBits)
+ {
+ case EData5:
+ dcb.ByteSize=5;
+ break;
+ case EData6:
+ dcb.ByteSize=6;
+ break;
+ case EData7:
+ dcb.ByteSize=7;
+ break;
+ case EData8:
+ dcb.ByteSize=8;
+ break;
+ }
+
+ switch(iConfig->iStopBits)
+ {
+ case EStop1:
+ dcb.StopBits=ONESTOPBIT;
+ break;
+ case EStop2:
+ dcb.StopBits=TWOSTOPBITS;
+ break;
+ }
+
+
+
+ TInt error_r=KErrNone;
+ if(!SetCommStateP(iCommPort,&dcb, UseSocket()))
+ error_r=GetLastError();
+
+// Clear any error we may have caused
+//
+ DWORD err,res;
+ COMSTAT s;
+ if (ClearCommError(iCommPort,&err,&s)==FALSE)
+ res=GetLastError();
+
+ }
+
+void DCommWins::Caps(TDes8 &aCaps) const
+//
+// Return the current capabilities
+//
+ {
+
+ GetWinsCommsCaps(aCaps);
+ }
+
+
+void DCommWins::WaitForEvent()
+ {
+
+ HANDLE objects[4];
+
+
+ iReadOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
+ iWriteOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
+ iSignalOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
+ objects[0]=iSignalOverLapped.hEvent; // iCommPort;
+ objects[1]=iCommThreadSem;
+ objects[2]=iWriteOverLapped.hEvent;
+ objects[3]=iReadOverLapped.hEvent;
+
+ FOREVER
+ {
+
+ _Log("#~ DCommWins::WaitForEvent() WaitForMultipleObjectsEx #1\n");
+ DWORD ret=WaitForMultipleObjectsEx(4,objects,FALSE,INFINITE,TRUE);
+ _Log2("#-- DCommWins::WaitForEvent(), event=%d\n", ret);
+
+ switch (ret)
+ {
+ case WAIT_OBJECT_0:
+ {
+ // EnterCritical();
+
+ _Log("#-- DCommWins::WaitForEvent(), event0\n");
+
+ if (iDataAvailableNotification)
+ {
+ DataAvailableCompletion(this);
+ iDataAvailableNotification = EFalse; //stop us repeatedly reporting it
+ }
+
+ TUint currentSignals = Signals();
+
+ //mask out all the signals but the ones we are interested in
+ iLineFail = (iFailSignals & currentSignals) != iFailSignals;
+ if (iLineFail)
+ {
+ //if we have the handshake options of
+ //KConfigFailDSR, KConfigFailDCD KFailConfigCTS set
+ //we need to do something if any of them are low so
+ //complete any outstanding ops with failure
+ if (iReadPending)
+ {
+ //we have a read to complete
+ iRXLineFail = ETrue;
+ PurgeComm(iCommPort, PURGE_RXABORT);
+ }
+
+ if (iWritePending)
+ {
+ //we have a write to complete
+ iTXLineFail = ETrue;
+ PurgeComm(iCommPort, PURGE_TXABORT);
+ }
+ }
+
+
+ //iSignalsRequested will only have bits set if outstanding request
+ TUint changed = (currentSignals ^ iSavedSignals) & iSignalsRequested;
+ if (changed)
+ {
+ SignalCompletion(this, KErrNone, changed, currentSignals);
+ iSavedSignals = currentSignals;
+ iSignalsRequested = 0; //stop us repeatedly reporting it.
+ //iSignalsRequested is setup in the call to notify
+ }
+
+ if (iWritePending == ETransmit0 && (currentSignals & KSignalCTS) != 0)
+ WriteCompletion(this, KErrNone, 0);
+
+ //request another notification event. All events are requested.
+ iSignalStatus=0;
+ DWORD commErrors;
+ BOOL res;
+ DWORD lastError = 0;
+ COMSTAT cstat;
+
+ do
+ {
+ ClearCommError(iCommPort,&commErrors,&cstat);
+ res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError != ERROR_IO_PENDING));
+
+ break;
+ }
+
+ case WAIT_OBJECT_0+1:
+//
+// iCommThreadSemaphore has been signalled
+//
+ _Log2("#-- DCommWins::WaitForEvent(), event1, driver command %d \n", iCommand);
+ DriverCommand(iCommand);
+ break;
+
+ case WAIT_OBJECT_0+2:
+ //
+ // Write completion
+ //
+ {
+ _Log("#-- DCommWins::WaitForEvent(), event2, write completion \n");
+
+ DWORD len = 0;
+ TInt error = KErrNone;
+ if (!GetOverlappedResult(iCommPort, &iWriteOverLapped, &len, FALSE))
+ error = Emulator::LastError();
+
+ COMSTAT s;
+ DWORD err = 0;
+ ClearCommError(iCommPort,&err,&s);
+
+ //if we are failing if one or more of CTS, DSR, DCD go low
+ if (iTXLineFail)
+ {
+ error = KErrCommsLineFail;
+ iTXLineFail = EFalse;
+ }
+ else if (err)
+ {
+ if (err & CE_FRAME)
+ error = KErrCommsFrame;
+ else if (err & CE_OVERRUN)
+ error = KErrCommsOverrun;
+ else if (err & CE_RXPARITY)
+ error = KErrCommsParity;
+ }
+
+ WriteCompletion(this, error, len);
+ break;
+ }
+
+ case WAIT_OBJECT_0+3:
+ //
+ // Read completion
+ //
+ {
+ //if(!iCommandEvent) break;
+
+ _Log("#-- DCommWins::WaitForEvent(), event3, read completion \n");
+
+ DWORD len = 0;
+ TInt error = KErrNone;
+
+ if(UseSocket() && iReadCancel)
+ {//-- socket read cancel occured
+ error = KErrCancel;
+ iReadCancel = EFalse;
+ }
+ else
+ {
+ if (!GetOverlappedResult(iCommPort, &iReadOverLapped, &len, FALSE))
+ error = Emulator::LastError();
+
+ COMSTAT s;
+ DWORD err = 0;
+ ClearCommError(iCommPort,&err,&s);
+
+ //if we are failing if one or more of CTS, DSR, DCD go low
+ if (iRXLineFail)
+ {
+ error = KErrCommsLineFail;
+ iRXLineFail = EFalse;
+ }
+ else if (err)
+ {
+ if (err & CE_FRAME)
+ error = KErrCommsFrame;
+ else if (err & CE_OVERRUN)
+ error = KErrCommsOverrun;
+ else if (err & CE_RXPARITY)
+ error = KErrCommsParity;
+ }
+ }
+
+ ReadCompletion(this, error, len);
+ break;
+ }
+
+ case WAIT_IO_COMPLETION:
+ _Log("#-- DCommWins::WaitForEvent(), Wait IO completion \n");
+
+ break;
+
+ default:
+ Emulator::LastError();
+ FAULT();
+ }
+ }
+ }
+
+void DCommWins::DriverCommand(TDriverCommand aCommand)
+//
+// Do a driver command - executed when the semaphore has been signalled in the comm port thread
+//
+ {
+
+ _Log2("#<- DCommWins::DriverCommand() :%d \n", aCommand);
+
+ switch (aCommand)
+ {
+ case ESetBreak:
+ SetCommBreak(iCommPort);
+ break;
+
+ case EClearBreak:
+ ClearCommBreak(iCommPort);
+ break;
+
+ case ETransmit0:
+
+ if (!iWritePending)
+ {
+ if ((iConfig->iHandshake & KConfigObeyCTS) != 0 && (Signals() & KSignalCTS) == 0)
+ iWritePending = ETransmit0;
+ else
+ DoWriteComplete(KErrNone);
+ }
+ break;
+
+ case ETransmit:
+
+ if (!iWritePending)
+ {
+ COMMTIMEOUTS ct;
+ int r = GetCommTimeouts(iCommPort, &ct);
+ ct.WriteTotalTimeoutConstant = 0;
+ ct.WriteTotalTimeoutMultiplier = 0;
+ r = SetCommTimeouts(iCommPort, &ct);
+
+ WriteFileP(iCommPort,iOutDes.Ptr(), iOutDes.Length(), &dummyLen, &iWriteOverLapped, UseSocket());
+ iWritePending = ETransmit;
+ }
+ break;
+
+ case EStart:
+ {
+ iSignalStatus=0;
+ iSignalStatus=0;
+
+ if(! UseSocket())
+ {
+
+ DWORD commErrors;
+ BOOL res;
+ DWORD lastError = 0;
+ COMSTAT cstat;
+
+ do
+ {
+ ClearCommError(iCommPort,&commErrors,&cstat);
+ res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
+ if (!res)
+ lastError = GetLastError();
+ }
+ while((!res) && (lastError != ERROR_IO_PENDING));
+ }
+ else
+ if(QueSocketRead() != KErrNone)
+ { // Inital Read Queue Failed :-(
+ // __DEBUGGER();
+ }
+
+ }
+ break;
+
+ case EStop:
+ // Flush last write
+ if(iWritePending == ETransmit)
+ {
+
+ _Log("#~ DCommWins::DriverCommand() WaitForSingleObject (case EStop)\n");
+
+ if(!UseSocket()) //-- can wait forewer on socket
+ WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+
+ FlushFileBuffers(iCommPort);
+ }
+ iWritePending=0;
+ // Fall through
+ case EStopNoDrain:
+ // Cancel any pending writes
+ if(iWritePending == ETransmit)
+ {
+ PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
+ _Log("#~ DCommWins::DriverCommand() WaitForSingleObject (case EStopNoDrain #1)\n");
+
+ if(!UseSocket()) //-- can wait forewer on socket
+ WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+ }
+ iWritePending=0;
+
+ iStopping=ETrue;
+
+ if(iRunning)
+ {
+ SetCommMaskP(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR, UseSocket());
+ _Log("#~ DCommWins::DriverCommand() WaitForSingleObject (case EStopNoDrain #2)\n");
+
+ if(!UseSocket()) //-- can wait forewer on socket
+ WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
+ }
+ break;
+
+ case EDie:
+ SignalDriverThread();
+ ExitThread(1);
+ break;
+
+ case EConfigure:
+ DoConfigure();
+ break;
+
+ case ETransmitCancel:
+ if (iWritePending == ETransmit)
+ PurgeComm(iCommPort, PURGE_TXABORT);
+// else if (iWritePending == ETransmit0)
+// {
+ // careful - this runs in the context of the kernel thread, not the event thread
+ iLdd->iTxError = KErrCancel;
+ iLdd->iTxCompleteDfc.Enque();
+// }
+ break;
+
+ case EReceive:
+ if (!iReadPending)
+ {
+ COMMTIMEOUTS ct;
+ int r = GetCommTimeouts(iCommPort, &ct);
+ ct.ReadIntervalTimeout = 0;
+ ct.ReadTotalTimeoutMultiplier = 0;
+ ct.ReadTotalTimeoutConstant = 0;
+ r = SetCommTimeouts(iCommPort, &ct);
+
+ //if we are doing a terminated read.... we need to do it a byte at a time!
+ if (iTerminatedRead)
+ {
+ iReadSoFar = 0;
+ ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped, UseSocket());
+ }
+ else
+ {
+ ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped, UseSocket());
+ }
+
+ iReadPending = EReceive;
+ }
+ break;
+
+ case EReceiveOneOrMore:
+ if (!iReadPending)
+ {
+ COMMTIMEOUTS ct;
+ int r = GetCommTimeouts(iCommPort, &ct);
+ ct.ReadIntervalTimeout = MAXDWORD;
+ ct.ReadTotalTimeoutMultiplier = MAXDWORD;
+ ct.ReadTotalTimeoutConstant = KReadOneOrMoreTimeout;
+ r = SetCommTimeouts(iCommPort, &ct);
+
+ //if we are doing a terminated read....
+ if (iTerminatedRead)
+ {
+ iReadSoFar = 0;
+ ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped, UseSocket());
+ }
+ else
+ {
+ ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped, UseSocket());
+ }
+
+ iReadPending = EReceiveOneOrMore;
+ }
+ break;
+
+ case EReceiveCancel:
+
+ if (iReadPending)
+ if(!UseSocket())
+ PurgeComm(iCommPort, PURGE_RXABORT);
+ else
+ {//-- force to resume comms event watcher thread and simulate read cancellation on the socket
+ iReadCancel=ETrue;
+ SetEvent(iReadOverLapped.hEvent);
+ }
+ else
+ if (iDataAvailableNotification)
+ DataAvailableNotificationCancel();
+
+
+ break;
+
+ case ENotifyDataAvailable:
+ {
+ iDataAvailableNotification = ETrue;
+ //setup the comms notifications for data available
+ break;
+ }
+
+ case ENotifySignals:
+ {
+ TUint currentSignals = Signals();
+ TUint changed = (currentSignals ^ iSavedSignals) & iSignalsWanted;
+ if (changed)
+ {
+ SignalCompletion(this, KErrNone, changed, currentSignals);
+ iSavedSignals = currentSignals;
+ iSignalsWanted = 0;
+ }
+ else
+ iSignalsRequested = iSignalsWanted; //checked when signals change
+ }
+ break;
+
+
+ default:
+ // Panic(EUnknownCommand);
+ break;
+ }
+ iCommand=EInvalidCommand;
+ SignalDriverThread();
+ }
+
+
+TDfcQue* DCommWins::DfcQ(TInt /*aUnit*/)
+ {
+ return Kern::DfcQue0();
+ }
+
+
+TInt DCommWins::ValidateConfig(const TCommConfigV01 &aConfig) const
+//
+// Check a config structure.
+//
+ {
+ if(aConfig.iRate & EBpsSpecial)
+ return KErrNotSupported;
+
+ switch (aConfig.iParity)
+ {
+ case EParityNone:
+ case EParityOdd:
+ case EParityEven:
+ break;
+ default:
+ return KErrNotSupported;
+ }
+ switch (aConfig.iRate)
+ {
+ case EBps50:
+ case EBps75:
+ case EBps134:
+ case EBps1800:
+ case EBps2000:
+ case EBps3600:
+ case EBps7200:
+ return KErrNotSupported;
+ default:
+ break;
+ };
+ return KErrNone;
+ }
+
+
+
+
+DECLARE_STANDARD_PDD()
+ {
+ return new DDriverComm;
+ }
+