toolsandutils/wintunnel/src_beech/d_cdrv.cpp
changeset 0 83f4b4db085c
child 1 d4b442d23379
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolsandutils/wintunnel/src_beech/d_cdrv.cpp	Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,1890 @@
+// 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:
+// Modified serial pdd that supports IP tunneling data from the emulator to  socket.
+// Beech specific version.
+// 
+//
+
+/**
+ @file
+*/
+
+#if defined(_UNICODE)
+#if !defined(UNICODE)
+#define UNICODE
+#endif
+#endif
+#define _WIN32_WINDOWS 0x0410 // Need NT4 / 98 or higher for the timer
+#define WIN32_LEAN_AND_MEAN
+#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
+#include <windows.h>
+#include <winsock2.h>
+#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
+#include <k32std.h>
+#include <e32wins.h>
+#include "uansi.h"
+#include "d_comm.h"
+
+//#include "iostream.h"
+
+// Dumps everything written to the serial port to temp files.
+//#define _LOG_OUTPUT
+
+
+//----------------------------------------------------------------
+//  logging macros. Just define WINTUN_PDD_LOGGING to enable debug trace
+//  require MSVCRTD.LIB
+#include <crtdbg.h>
+
+//#define WINTUN_PDD_LOGGING 
+
+#ifdef WINTUN_PDD_LOGGING 
+    
+    #pragma warning( disable : 4127 ) 
+
+    #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
+
+const TInt KReadBufSize = 1024;
+const TInt KWriteBufSize = 16;
+//const TInt KWinNTReadBufSize = 1024;
+const TInt KWinNTReadBufSize = 1500;
+const TInt KWinNTWriteBufSize = KWriteBufSize;
+static DWORD dummyLen=0;
+
+enum TDCommWinsFault 
+	{
+	EWindowsUnexpectedError,
+	EUnknownCommand,
+	EBadIOLen,
+	EEofOnSerial,
+	EWriteEarlyCompletion,
+	ELineErrorNotReported,
+	};
+
+class DDriverComm : public DPhysicalDevice
+	{
+public:
+	DDriverComm();
+	virtual TInt Install();
+	virtual TInt Remove();
+	virtual void GetCaps(TDes8 &aDes) const;
+	virtual CBase *CreateL(TInt aUnit,const TDesC *anInfo,const TVersion &aVer);
+	};
+
+class DCommWins : public DComm
+	{
+public:
+	enum TDriverCommand {ESetBreak,EClearBreak,ETransmit,
+						EGetSignals,ESetSignals,EConfigure,
+						EStop,EStopNoDrain,EStart,EDie,EInvalidCommand};
+public:
+	DCommWins();
+	~DCommWins();
+	virtual TInt Start();
+	virtual void Stop(TStopMode aMode);
+	virtual void Break(TBool aState);
+	virtual void EnableTransmit();
+	virtual TUint Signals() const;
+	virtual void SetSignals(TUint aSetMask,TUint aClearMask);
+	virtual TInt Validate(const TCommConfigV01 &aConfig) const;
+	virtual void Configure(TCommConfigV01 &aConfig);
+	virtual void DoConfigure();
+	virtual void CheckConfig(TCommConfigV01& aConfig);
+	virtual void Caps(TDes8 &aCaps) const;
+	virtual void EnableInterrupts();
+	virtual void DisableInterrupts();
+	TInt CompleteSlowOpen(DThread *aThread,TRequestStatus *aReqStat);
+	void EnterCritical();
+	void LeaveCritical();
+	TInt DoCreate(TInt aUnit,const TDesC *anInfo);
+	void WaitForEvent();
+	void DriverCommand(TDriverCommand aCommand);
+	void DoTransmit(TInt aByteCount);
+	void DoReceive(TInt aByteCount);
+	void RunCommThread(TDriverCommand aCommand);
+	inline void SignalDriverThread();
+	TInt DoTransmitIsr(TInt anOffset);
+	void DoReceiveIsr(TUint aCharAndMask);
+	void DoStateIsr();
+	
+    void SetTimer(const TUint aTimeOut); 
+    void CancelTimer(); 
+	
+	
+private:
+	TBool iWritePending;
+	TBool iReadPending;
+
+    TBool iStopping;
+	// TBool iReading;
+	TBool iRunning;
+	TDriverCommand iCommand;
+	TCommConfigV01 *iConfig;
+	TUint iSignals;
+	TUint8 iInBuf[KReadBufSize];
+	DWORD iNumInChars;
+	TUint8 iOutBuf[KWriteBufSize];
+	DWORD iNumOutChars;
+	HANDLE iThread;
+	HANDLE iCommThreadSem;
+	HANDLE iDriverThreadSem;
+	HANDLE iCommPort;
+    HANDLE iWaitableTimer; 
+    LARGE_INTEGER iTimeOut; 
+	DWORD iThreadID;
+	DWORD iSignalStatus;
+	OVERLAPPED iReadOverLapped;
+	OVERLAPPED iWriteOverLapped;
+	OVERLAPPED iSignalOverLapped;
+#if defined (_DEBUG)
+	TInt iUnit;
+	HANDLE iLogFile;
+#endif
+#if defined (_LOG_OUTPUT)
+	HANDLE iWritesHandle;
+	HANDLE iReadsHandle;
+#endif
+	CRITICAL_SECTION iCriticalSection;
+	TInt iIntRefCount;
+	TBool iSkipTransmitIsrNextTime;
+
+	SOCKET iSocket;
+	
+
+    /** @return ETrue if we use socket instead of a real COM port */
+    TBool inline UseSocket(void) const
+        {return  (iSocket != INVALID_SOCKET) && (iSocket != NULL); }
+    
+    TInt QueSocketRead();
+    
+    TBool GetComPortMapping(LPCSTR aFileName, TInt aPortNum, TDes8& aPortMapStr);
+
+	};
+
+void Panic(TDCommWinsFault aFault)
+//
+// Panic the driver 
+//
+	{
+
+	Plat::Panic(_L("DCommWins"),aFault);
+	}
+
+
+TInt MapWinError(TInt aErrCode)
+{
+	switch (aErrCode)
+	{
+	case ERROR_INVALID_USER_BUFFER:
+	case ERROR_NOT_ENOUGH_MEMORY:
+	case ERROR_INSUFFICIENT_BUFFER:
+		return(KErrNoMemory);
+	case ERROR_ACCESS_DENIED:
+		return(KErrAccessDenied);
+	case ERROR_NOT_SUPPORTED:
+		return(KErrNotSupported);
+	default:
+		return(KErrGeneral);
+	} 
+}
+
+TInt MapWinError()
+//
+// Make an E32 error from the dodgy old thing windows tells us
+//
+{
+	DWORD winErr=GetLastError();
+    return MapWinError(winErr);
+}
+
+TUint commThread(DCommWins *comm)
+//
+// Comm thread entry point
+//
+	{
+
+	comm->WaitForEvent();
+	return 0;
+	}
+
+//VOID WINAPI ReadComplete(DWORD anErr,DWORD numBytes,LPOVERLAPPED anOverLapped)
+//
+// Windows read completion routine
+//
+//	{
+//
+//	if (numBytes>KReadBufSize)
+//		Panic(EBadIOLen); 
+//	if (anErr==ERROR_HANDLE_EOF)
+//		Panic(EEofOnSerial);
+//	((DCommWins *)(anOverLapped->hEvent))->DoReceive(numBytes);
+//	}
+
+VOID WINAPI WriteCompletion(DCommWins *aDrv, DWORD anErr,DWORD numBytes)
+//
+// Windows read completion routine
+//
+	{
+
+	if (numBytes>KWriteBufSize+1)	// May have written an Xon
+		Panic(EBadIOLen); 
+	if (anErr==ERROR_HANDLE_EOF)
+		Panic(EEofOnSerial);
+	aDrv->DoTransmit(numBytes);
+	}
+
+BOOL WINAPI EscapeCommFunctionP(HANDLE hFile,DWORD dwFunc, BOOL bUseSocket)
+//
+// Protected Set/Clear modem control signals: protects against this operation being cancelled by another thread
+//
+    {
+	if(bUseSocket)
+        return TRUE;
+
+    DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=EscapeCommFunction(hFile,dwFunc))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+BOOL WINAPI GetCommModemStatusP(HANDLE hFile,LPDWORD lpModemStat, BOOL bUseSocket)
+//
+// Protected read modem control signals: protects against this operation being cancelled by another thread
+//
+	{
+	if(bUseSocket)
+        return TRUE;
+
+	DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=GetCommModemStatus(hFile,lpModemStat))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+BOOL WINAPI GetCommStateP(HANDLE hFile,LPDCB lpDCB, BOOL bUseSocket)
+//
+// Retrieves the current control settings for a specified communications device: protected against
+// this operation being cancelled by another thread
+//
+	{
+	if(bUseSocket)
+        return TRUE;
+
+	DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=GetCommState(hFile,lpDCB))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+BOOL WINAPI SetCommStateP(HANDLE hFile,LPDCB lpDCB, BOOL bUseSocket)
+//
+// Configures a communications device according to the specifications in a device-control block: protected against
+// this operation being cancelled by another thread
+//
+	{
+	if(bUseSocket)
+        return TRUE;
+
+	DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=SetCommState(hFile,lpDCB))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+BOOL WINAPI SetCommMaskP(HANDLE hFile,DWORD dwEvtMask, BOOL bUseSocket)
+//
+// Specifies a set of events to be monitored for a communications device: protected against
+// this operation being cancelled by another thread
+//
+	{
+	if(bUseSocket)
+        return TRUE;
+
+	DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=SetCommMask(hFile,dwEvtMask))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+BOOL WINAPI WriteFileP(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)
+//
+// Writes data to device pointed by hFile: protected against
+// this operation being cancelled by another thread
+//
+	{
+	DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=WriteFile(hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+BOOL WINAPI ReadFileP(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
+//
+// Writes data to device pointed by hFile: protected against
+// this operation being cancelled by another thread
+//
+	{
+	DWORD err,res,res1;
+	COMSTAT s;
+	BOOL result;
+
+	result=FALSE;
+	do
+		{
+		ClearCommError(hFile,&err,&s);
+		if((res1=ReadFile(hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped))==FALSE)
+			res=GetLastError();
+		else
+			{
+			result=TRUE;
+			break;
+			}
+		}
+	while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+	return(result);
+	}
+
+DDriverComm::DDriverComm()
+//
+// Constructor
+//
+	{
+
+#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()
+//
+// Install the device driver.
+//
+	{
+#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()
+//
+// Remove the device driver.
+//
+	{
+	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=0x1ff; // All handshakes
+	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
+//
+// Return the drivers capabilities.
+//
+	{
+
+	GetWinsCommsCaps(aDes);
+	}
+
+CBase *DDriverComm::CreateL(TInt aUnit,const TDesC *anInfo,const TVersion &aVer)
+//
+// Create a channel on the device.
+//
+	{
+
+	if (!User::QueryVersionSupported(iVersion,aVer))
+		User::Leave(KErrNotSupported);
+	DCommWins *pD=new(ELeave) DCommWins;
+	TInt ret=pD->DoCreate(aUnit,anInfo);
+	if (ret!=KErrNone)
+		{
+		delete pD;
+		User::Leave(ret);
+		}
+	return(pD);
+	}
+
+
+
+void DCommWins::DoTransmit(TInt aByteCount)
+//
+// Called from write completion routine
+//
+	{
+
+	if(aByteCount==0)
+		{
+		DWORD err,res;
+		COMSTAT s;
+		if (!UseSocket() && ClearCommError(iCommPort,&err,&s)==FALSE)
+			res=GetLastError();
+		}
+	__ASSERT_ALWAYS(iNumOutChars-aByteCount<=KWriteBufSize,Panic(EWriteEarlyCompletion));
+#if defined (_LOG_WRITES)
+		TBuf<0x40> buf;
+		DWORD dummy;
+		buf.Format(_L("write complete %d\r\n"),aByteCount);
+		WriteFile(iLogFile,buf.PtrZ(),buf.Length(),&dummy,NULL);
+#endif
+//
+	iNumOutChars-=aByteCount;
+	if (iCommand==EStop)
+		return;
+	if (iSkipTransmitIsrNextTime)
+		{
+		iSkipTransmitIsrNextTime=EFalse;
+		}
+	else
+		{
+		while (iNumOutChars<KWriteBufSize)
+			{
+			iSkipTransmitIsrNextTime=!DoTransmitIsr(iNumOutChars);
+			if (iSkipTransmitIsrNextTime)
+				break;
+			iNumOutChars++;
+			}
+		}
+	if(iNumOutChars>0)
+		{
+//		WriteFileEx(iCommPort,iOutBuf,iNumOutChars,&iWriteOverLapped,WriteComplete);
+		WriteFile(iCommPort,iOutBuf,iNumOutChars, &dummyLen, &iWriteOverLapped);
+		iWritePending=ETrue;
+
+#if defined (_LOG_OUTPUT)
+		DWORD dummy;
+		WriteFile(iWritesHandle,iOutBuf,iNumOutChars,&dummy,NULL);
+#endif
+#if defined (_LOG_WRITES)
+		buf.Format(_L("Writing %d\r\n"),iNumOutChars);
+		WriteFile(iLogFile,buf.PtrZ(),buf.Length(),&dummy,NULL);
+#endif
+
+		}
+	else
+		iWritePending=EFalse;
+	}
+
+/*
+For reference only:
+Returned from 2nd param to ClearCommError (err below)
+#define CE_RXOVER           0x0001  // Receive Queue overflow
+#define CE_OVERRUN          0x0002  // Receive Overrun Error
+#define CE_RXPARITY         0x0004  // Receive Parity Error
+#define CE_FRAME            0x0008  // Receive Framing error
+#define CE_BREAK            0x0010  // Break Detected
+#define CE_TXFULL           0x0100  // TX Queue is full
+#define CE_PTO              0x0200  // LPTx Timeout
+#define CE_IOE              0x0400  // LPTx I/O Error
+#define CE_DNS              0x0800  // LPTx Device not selected
+#define CE_OOP              0x1000  // LPTx Out-Of-Paper
+#define CE_MODE             0x8000  // Requested mode unsupported
+
+#define IE_BADID            (-1)    // Invalid or unsupported id
+#define IE_OPEN             (-2)    // Device Already Open
+#define IE_NOPEN            (-3)    // Device Not Open
+#define IE_MEMORY           (-4)    // Unable to allocate queues
+#define IE_DEFAULT          (-5)    // Error in default parameters
+#define IE_HARDWARE         (-10)   // Hardware Not Present
+#define IE_BYTESIZE         (-11)   // Illegal Byte Size
+#define IE_BAUDRATE         (-12)   // Unsupported BaudRate
+*/
+
+//void DCommWins::DoReceive(TInt aByteCount)
+//
+// Called from read completion routine 
+//
+//	{
+//	if(aByteCount==0)
+//		{
+//		DWORD err=0,res;
+//		COMSTAT s;
+//		if (iCommPort && ClearCommError(iCommPort,&err,&s)==FALSE)
+//			res=GetLastError();
+//		if(err)
+//			{
+//			Panic(ELineErrorNotReported);
+//			}
+//		}
+//	TInt i=0;
+//	
+//	while(i<aByteCount)
+//		{
+//		DoReceiveIsr(iInBuf[i]);
+//		i++;
+//		}
+//#if defined (_LOG_OUTPUT)
+//		DWORD dummy;
+//		WriteFile(iReadsHandle,iInBuf,aByteCount,&dummy,NULL);
+//#endif 
+//	if(iStopping)
+//		{
+//		iStopping=EFalse;
+//		return;
+//		}
+//
+//	if (!ReadFileEx(iCommPort,iInBuf,KReadBufSize,&iReadOverLapped,ReadComplete))
+//		{
+//		TInt r=GetLastError();
+//		Panic(EWindowsUnexpectedError);
+//		}
+//	}
+
+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)
+		{
+		DriverCommand(aCommand);
+		WaitForSingleObject(iDriverThreadSem,INFINITE);
+		}
+	else
+		{
+		Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
+		
+		if (ReleaseSemaphore(iCommThreadSem,1,NULL)==FALSE)
+			{
+			DWORD ret=GetLastError();
+			ret=ret;
+			Panic(EWindowsUnexpectedError);
+			}
+		WaitForSingleObject(iDriverThreadSem,INFINITE);
+		}
+	}
+
+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()
+//
+// Constructor
+//
+	{
+//	iRunning=EFalse;
+//	iCommand=ESetBreak;
+//	iSignals=0;
+//	iInBuf=0;
+//	iOutBuf=0;
+//	iThread=NULL;
+//	iCommThreadSem=NULL;
+//	iCommPort=NULL;
+//	iThreadID=0;
+	iWritePending = EFalse;
+	iReadPending  = EFalse;
+
+	Mem::FillZ(&iReadOverLapped,sizeof(OVERLAPPED));
+	Mem::FillZ(&iWriteOverLapped,sizeof(OVERLAPPED));
+	__DECLARE_NAME(_S("DCommWins"));
+#ifdef _DEBUG_DEVCOMM
+	iTxIntCount = 0;
+	iRxIntCount = 0;
+	iTxErrCount = 0;
+	iRxErrCount = 0;
+#endif
+	iIntRefCount = 0;
+	iSocket = INVALID_SOCKET;
+
+    _Log("# ------------------------------------------------\n");
+	_Log("# DCommWins::DCommWins()\n");
+    
+	}
+#pragma warning( default : 4705 )
+
+/**
+*   Read serial port mapping from ini file (dComm.ini usually)
+*
+*   @param  aFileName   ini full file path descriptor
+*   @param  aPortNum    serial port number (e.g. 0 for COMM::0)
+*   @param  aPortMapStr descriptor for returned port mapping (e.g. "10.35.2.53:110)
+*   
+*   @return ETrue if the parameter found and everything is OK.
+*/
+TBool DCommWins::GetComPortMapping(LPCSTR aFileName, TInt aPortNum, TDes8& aPortMapStr)
+{
+    TBool   bRes = ETrue;
+	TInt    fileSize;
+    LPVOID	pFileData=NULL;
+
+    //--  open dcomm.ini file
+    HANDLE hFile=CreateFileA(aFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (!hFile || hFile == INVALID_HANDLE_VALUE)
+	{//-- can't open file, maybe it is just not present
+		bRes = EFalse;
+		goto CleanUp;
+	}
+
+    //-- get file size
+    fileSize = GetFileSize(hFile, NULL);
+    if (fileSize == INVALID_FILE_SIZE || !fileSize)
+    {//-- something is wrong with file size
+		bRes = EFalse;
+		goto CleanUp;
+    }
+    
+    //-- allocate data for buffer 
+	// fileSize+1 to ensure zero-termination of file, since Windows98 might use
+	// a dirty page of memory.  VirtualAlloc initializes memory to zero
+    pFileData = VirtualAlloc(NULL, fileSize+1, MEM_COMMIT, PAGE_READWRITE);
+    if(! pFileData)
+    {//-- something is wrong with memory allocation
+		bRes = EFalse;
+		goto CleanUp;
+    }
+
+    //-- read whole file into buffer
+    DWORD bytesRead;    
+
+    if (! ReadFile(hFile, pFileData, fileSize, &bytesRead, NULL))
+        bRes = EFalse;
+    else
+    {//-- parse file line by line looking for the appropriate port 
+	    LPSTR linePtr=(LPSTR)pFileData;
+		_LIT8(KCommToken, "COMM::");
+        bRes = EFalse;
+
+
+        while(linePtr && *linePtr)
+		{
+			//-- skip spaces at the beginning of the current line
+            while (*linePtr && (*linePtr == '\r' || *linePtr == '\n' || *linePtr == ' ' || *linePtr =='\t'))
+			{
+				++linePtr;
+				--bytesRead;
+			}
+
+            //-- find the end of the line
+			TPtrC8 line((unsigned char*)linePtr, bytesRead);
+            TInt len;
+			for (len = 0; len < line.Length() && (line[len] != '\r' && line[len] != '\n'); ++len)
+				;
+
+			line.Set(line.Left(len));
+			bytesRead -= line.Length();
+			linePtr += line.Length();
+
+            //-- parse the line
+			TLex8   lex(line);
+			TPtrC8  commname (lex.NextToken());
+			if(commname.Length() <= KCommToken().Size())
+				continue; // not enough chars
+			if(commname[0] == '#')
+				continue; // comment line
+
+			if (commname.Left(KCommToken().Size()).CompareF(KCommToken) != 0)
+				continue; // unreconised option. Should log?!?
+    
+            //-- extract comm port number
+    		TLex8 numLex(commname.Mid(KCommToken().Size()));
+			TInt commNum;
+			if(numLex.Val(commNum) != KErrNone || commNum != aPortNum)
+				continue;
+
+			//-- extract comm port mapping substring
+            lex.SkipSpace();
+            aPortMapStr.Copy(lex.Remainder());
+            aPortMapStr.PtrZ();
+            bRes = ETrue;
+
+            break;
+        }//while(linePtr && *linePtr)
+    }
+
+    
+  CleanUp:
+
+    CloseHandle(hFile);
+    VirtualFree(pFileData, 0, MEM_RELEASE);
+
+    return bRes;
+}
+
+
+TInt DCommWins::DoCreate(TInt aUnit,const TDesC * /*anInfo*/)
+//
+// Create the comms driver.
+//
+	{
+    _Log("# DCommWins::DoCreate()\n");
+
+	InitializeCriticalSection(&iCriticalSection);
+
+#if defined (__COM_ONE_ONLY__)
+	if (aUnit!=0)
+		return KErrNotSupported;
+#elif defined (__COM_TWO_ONLY__)
+	if (aUnit!=1)
+		return KErrNotSupported;
+#endif
+
+    //-- get full path for the DComm.ini configuration file
+	TBuf8<MAX_PATH> iniFileName;
+    iniFileName.Copy(EmulatorDataPath());
+	iniFileName.Append(_L8("DComm.ini"));
+    LPCSTR  pszIniFle = (LPCSTR)iniFileName.PtrZ();
+
+    //-- get com port mapping string
+	TBuf8<MAX_PATH> strPortMapping;
+    TBool bFound = GetComPortMapping(pszIniFle, aUnit, strPortMapping);
+
+    if(bFound)
+    {//-- comm port mapping string is found in cofiguration file, we are dealing with sockets now
+    
+        //-- try to locate port number after colon
+        TInt nColonPos = strPortMapping.Locate(':');
+        if(nColonPos != KErrNotFound)
+        {// Found a ':' ... must be a TCP name & port no.
+            TPtrC8 hostAddr(strPortMapping.Left(nColonPos));
+
+            ((char*)strPortMapping.Ptr())[nColonPos] = 0; // replace : with a null term
+
+		    TLex8 portLex (strPortMapping.Mid(nColonPos + 1));
+		    TInt port = 0;
+		    portLex.Val(port);
+
+
+            //-- initialize socket
+
+		    WORD    wVersionRequested;
+		    WSADATA wsaData;
+		    int err; 
+		    wVersionRequested = MAKEWORD(2, 0); 
+		    err = WSAStartup(wVersionRequested, &wsaData);
+		    if (err != 0)
+                return MapWinError(WSAGetLastError());
+
+		    iSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
+		    if(iSocket == INVALID_SOCKET)
+                return MapWinError(WSAGetLastError());
+            
+            _Log2("# DCommWins: created socket id: %d\n", iSocket );
+		    
+            sockaddr_in sin;
+
+		    char* devname = (char*)(strPortMapping.Ptr());
+		    u_long nRemoteAddr = inet_addr(devname);
+		    
+            if (nRemoteAddr != INADDR_NONE)
+			{
+			    sin.sin_addr.s_addr = nRemoteAddr;
+			}
+		    else
+			{
+			    struct hostent FAR * hostaddr = gethostbyname (devname);
+			    if(hostaddr == NULL)
+				    return MapWinError(WSAGetLastError());
+			    
+                sin.sin_addr.s_addr = *((u_long*)hostaddr->h_addr_list[0]);
+			}
+
+		    sin.sin_family = AF_INET;
+		    sin.sin_port = htons(TUint16(port));
+
+		    err = WSAConnect(iSocket, (sockaddr*)&sin, sizeof(sin), 0, 0, 0, 0);
+		    if(err)
+                return MapWinError(WSAGetLastError());
+
+            _Log2("# DCommWins: socket connected to the port: %d\n", port);
+
+		    iCommPort = (void*)iSocket;
+            
+        }
+    }
+   
+                        
+    //-----------------------------------------
+
+    if(! UseSocket())
+    {//-- use PC serial port as usual
+        //-- open Windows serial port
+	    TBuf8<0x10> n;
+	    n.Format(_L8("\\\\.\\COM%d"),aUnit+1);
+	    iCommPort=CreateFileA((LPCSTR)n.PtrZ(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
+	    if (iCommPort==INVALID_HANDLE_VALUE)	
+		    {	
+	    //	Reused code from MapWinError() rather than adding an extra case 
+	    //	to MapWinError() 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;
+	    if (!GetCommStateP(iCommPort,&dcb,UseSocket()))
+		    return MapWinError();
+
+	    dcb.fDtrControl=DTR_CONTROL_DISABLE;
+	    dcb.fRtsControl=RTS_CONTROL_DISABLE;
+	    dcb.fAbortOnError=TRUE;	// Tell me about your parity problems luvvy
+	    dcb.fParity=TRUE;
+	    dcb.fBinary=TRUE;
+	    dcb.fOutxCtsFlow=FALSE;
+	    dcb.fOutxDsrFlow=FALSE;  
+	    dcb.fDsrSensitivity=FALSE;
+	    dcb.fTXContinueOnXoff=TRUE;
+	    dcb.fOutX=FALSE;
+	    dcb.fInX=FALSE;
+	    dcb.fErrorChar=FALSE;
+	    dcb.fNull=FALSE;
+    //
+    //	dcb.ByteSize;		// number of bits/byte, 4-8
+    //	dcb.Parity;			// 0-4=no,odd,even,mark,space
+    //	dcb.StopBits;		// 0,1,2 = 1, 1.5, 2
+    //	dcb.XonChar;		// Tx and Rx XON character
+    //	dcb.XoffChar;		// Tx and Rx XOFF character
+    //	dcb.ErrorChar;		// error replacement character
+    //	dcb.EofChar;		// end of input character
+    //	dcb.EvtChar;
+    //
+	    if (!SetCommStateP(iCommPort,&dcb, UseSocket()))
+		    return MapWinError();
+
+	    EscapeCommFunctionP(iCommPort,0,UseSocket());
+
+    //
+    // Could add EV_RXCHAR|EV_RXFLAG|EV_TXEMPTY to the following
+    // mask too and get all chars through the call to WaitForAnyObject
+    // rather then the completion routine followed by a manual read
+    //
+	    if (!SetCommMaskP(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR,UseSocket()))
+		    return MapWinError();
+
+	    if(!SetupComm(iCommPort,KWinNTReadBufSize,KWinNTWriteBufSize))
+		    return MapWinError();
+
+    //
+    // The serial port seems to open with the error condition set
+    //
+
+	    DWORD err,res;
+	    COMSTAT s;
+	    if (ClearCommError(iCommPort,&err,&s)==FALSE)
+		    res=GetLastError();
+    }//if(! UseSocket())
+
+	if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+	    return MapWinError();
+    
+    if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+	    return MapWinError();
+
+    if ((iWaitableTimer=CreateWaitableTimer(NULL, FALSE, NULL))==NULL)
+        return MapWinError();
+
+	if ((iThread=CreateThread(NULL,0x4000,(LPTHREAD_START_ROUTINE)commThread,(void *)this,CREATE_SUSPENDED,&iThreadID))==NULL)
+	    return MapWinError();
+
+    
+
+#if defined (_LOG_WRITES)
+	TBuf8<0x40> logName;
+	logName.Format(_L8("C:\\tmp\\log%d.tmp"),iUnit);
+	DWORD fileErr;
+	if((iLogFile=CreateFileA((char *)logName.PtrZ(),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
+		fileErr=GetLastError();
+#endif
+#if defined (_LOG_OUTPUT)
+	TBuf8<0x40> fileName;
+	DWORD fileErr;
+	fileName.Format(_L8("C:\\tmp\\Writes%d.tmp"),iUnit);
+	if((iWritesHandle=CreateFileA((char *)fileName.PtrZ(),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
+		fileErr=GetLastError();
+	fileName.Format(_L8("C:\\tmp\\Reads%d.tmp"),iUnit);
+	if((iReadsHandle=CreateFileA((char *)fileName.PtrZ(),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
+		fileErr=GetLastError();
+#endif
+	
+	SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
+	return(KErrNone);
+	}
+
+DCommWins::~DCommWins()
+//
+// Destruct
+//
+	{
+	if (iThread)
+		{
+		if (! iRunning)
+			{
+			__ASSERT_ALWAYS(
+				ResumeThread(iThread) != 0xffffffff,
+				User::Panic(_L("Wins comm error"), 0));
+			}
+
+		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 (iWaitableTimer)
+        CloseHandle(iWaitableTimer);
+
+	if (iReadOverLapped.hEvent)
+		CloseHandle(iReadOverLapped.hEvent);
+
+	if (iWriteOverLapped.hEvent)
+		CloseHandle(iWriteOverLapped.hEvent);
+
+	if (iSignalOverLapped.hEvent)
+		CloseHandle(iSignalOverLapped.hEvent);
+
+	if (iThread)
+		CloseHandle(iThread);
+
+	DeleteCriticalSection(&iCriticalSection);
+	}
+
+TInt DCommWins::Start()
+//
+// Start receiving characters
+//
+	{
+
+	__ASSERT_ALWAYS(ResumeThread(iThread)!=0xffffffff,User::Panic(_L("Wins comm error"),0));
+//	if (ResumeThread(iThread)==0xffffffff)
+//		return(MapWinError());
+	iRunning=ETrue;
+	RunCommThread(EStart);
+	return(KErrNone);
+	}
+
+void DCommWins::Stop(TStopMode aMode)
+//
+// Stop receiving characters
+//
+	{
+
+	iSkipTransmitIsrNextTime=EFalse;
+	RunCommThread((aMode==EStopEmergency) ? EStopNoDrain : EStop);
+	SuspendThread(iThread);
+	iRunning=EFalse;
+	iNumInChars=iNumOutChars=0;
+	}
+
+void DCommWins::Break(TBool aState)
+//
+// Assert a break signal
+//
+	{
+
+	if (aState)
+		RunCommThread(ESetBreak);
+	else
+		RunCommThread(EClearBreak);
+	}
+
+void DCommWins::EnableTransmit()
+//
+// Start transmitting characters
+//
+	{
+	RunCommThread(ETransmit);
+	}
+
+
+TUint DCommWins::Signals() const
+//
+// Return the current signals state
+//
+	{
+	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;
+	CONST_CAST(DCommWins*,this)->iSkipTransmitIsrNextTime=EFalse;
+	return(status|iSignals);
+	}
+
+void DCommWins::SetSignals(TUint aSetMask,TUint aClearMask)
+//
+// Set the state of the output signals
+//
+	{
+
+    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());
+		}
+        
+        _Log2("#~DCommWins::SetSignals, iSignals has become=0x%x\n", iSignals);
+	}
+
+void DCommWins::CheckConfig(TCommConfigV01& /*aConfig*/)
+	{
+	// Do nothing
+	}
+
+
+TInt DCommWins::CompleteSlowOpen(DThread *aThread,TRequestStatus *aReqStat)
+	{
+	// Should never be called
+	aThread->RequestComplete(aReqStat,KErrNone);
+	return(KErrNone);
+	}
+
+TInt DCommWins::Validate(const TCommConfigV01 &aConfig) const
+//
+// Confirm that aConfig is a valid configuration.
+//
+	{
+
+	if (aConfig.iSIREnable==ESIREnable)
+		return KErrNotSupported;
+
+	if (aConfig.iRate&KCapsBpsSpecial)
+		return(KErrNotSupported);
+	switch (aConfig.iRate)
+		{
+	case EBps50:
+	case EBps2000:
+	case EBps3600:
+		return(KErrNotSupported);
+		};
+	return(KErrNone);
+	}
+
+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
+//
+	{
+
+
+
+	DCB dcb;
+	if (!GetCommStateP(iCommPort,&dcb, UseSocket()))
+		return;
+
+    if(iRunning)
+        {
+        SetCommMaskP(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR, UseSocket());
+        WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
+        }
+
+//	
+// Need only worry about the framing and speed.
+//				   
+	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->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;
+		}
+
+	switch (iConfig->iParity)
+		{
+	case EParityNone:
+		dcb.Parity=NOPARITY;
+		break;
+	case EParityEven:
+		dcb.Parity=EVENPARITY;
+		break;
+	case EParityOdd:
+		dcb.Parity=ODDPARITY;
+		break;
+		}
+
+	// make sure that SetCommState won't change the state of the Modem signals
+	TUint prov=iSignals&KSignalRTS;
+	if(prov)
+		dcb.fRtsControl=RTS_CONTROL_ENABLE;
+	else
+		dcb.fRtsControl=RTS_CONTROL_DISABLE;
+
+	prov=iSignals&KSignalDTR;
+	if(prov)
+		dcb.fDtrControl=DTR_CONTROL_ENABLE;
+	else
+		dcb.fDtrControl=DTR_CONTROL_DISABLE;
+		
+	TInt error_r=KErrNone;
+	if(!SetCommStateP(iCommPort,&dcb, UseSocket()))
+		error_r=GetLastError();
+//	SetSignals(iSignals, ~iSignals);	// For NT 4 -> redundant (see above comments on preserving Modem control signals)
+//
+// Clear any error we may have caused
+//
+	DWORD err,res;
+	COMSTAT s;
+	if (ClearCommError(iCommPort,&err,&s)==FALSE)
+		res=GetLastError();
+
+    if(iRunning)
+        {
+        if(!WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped))
+            {
+            TInt i=50;
+            while(--i)
+                {
+                if(WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped))
+                    break;
+                }
+            }
+        }
+	}
+
+void DCommWins::Caps(TDes8 &aCaps) const
+//
+// Return the current capabilities
+//
+	{
+
+	GetWinsCommsCaps(aCaps);
+	}
+
+void DCommWins::EnableInterrupts()
+//
+// Wake the comms thread up
+//
+	{
+	LeaveCritical();
+//	if (ResumeThread(iThread)==0xFFFFFFFF)
+//		{
+//		DWORD err=GetLastError();
+//		Panic(EWindowsUnexpectedError);
+//		}
+	iSkipTransmitIsrNextTime=EFalse;
+	}
+
+void DCommWins::DisableInterrupts()
+//
+// Suspend the thread (assuming we're not it...)
+//
+	{
+	EnterCritical();
+//	if(GetCurrentThreadId()!=iThreadID)
+//		if (SuspendThread(iThread)==0xFFFFFFFF)
+//			{
+//			DWORD err=GetLastError();
+//			Panic(EWindowsUnexpectedError);
+//			}
+	}
+
+/**
+    Associate event with our socket
+*/
+TInt DCommWins::QueSocketRead()
+	{
+	if(WSAEventSelect(iSocket, iReadOverLapped.hEvent, FD_READ))
+		{// Some error?!?
+		DWORD res = WSAGetLastError();
+		return res;
+		}
+	return KErrNone;
+
+	}
+
+
+void DCommWins::WaitForEvent()
+//
+// Comm port thread - wait for serial port and semaphore
+//
+	{
+
+	HANDLE objects[5];
+
+
+	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;
+    objects[4]=iWaitableTimer;
+
+	FOREVER
+		{
+		DWORD waitTimeout = INFINITE; // Default timeout 
+		if(iReadPending) // If we have a queued read event, we need to check periodically if it can be carried out.
+			{
+			waitTimeout = 150; 
+			}
+		
+		// Once an event is signalled and WaitFor.. returns, it is reset by WaitFor.. just before it returns.
+		// This means that once a read on the socket is signalled. we absolutely must read from it (eventually).
+		// Otherwise, the read event remains reset and no further reads are signalled, even if data arrives. 
+		// This means that if we cannot read immediately,we MUST queue the read, and carry it out sometimes in the future.
+		DWORD ret=WaitForMultipleObjectsEx(5,objects,FALSE,waitTimeout,TRUE);
+				
+		// If the wait for an event has timed out, AND we have a queued read, try to carry out the read.
+		// If we have not timed out, carry out the operation as usual:
+		// it cannot be a read, but it may be something which enables us to read later.
+		if(ret == WAIT_TIMEOUT && iReadPending)
+			{			
+			ret = WAIT_OBJECT_0 + 3; // Fall through to the read. 			
+			}
+		
+		switch (ret)
+			{
+		case WAIT_OBJECT_0:
+			ASSERT(iCommPort);
+			EnterCritical();
+			DWORD commErrors;
+			COMSTAT cstat;
+//	
+// iCommPort has completed other than read/write - could be either error or line status change
+//
+			if ((iSignalStatus&EV_ERR) || (iSignalStatus&EV_RXCHAR))
+				{ 
+				ClearCommError(iCommPort,&commErrors,&cstat);
+				if (cstat.cbInQue)
+					{
+//
+// Drain the input buffer
+//				
+					while (cstat.cbInQue>0)
+						{
+                        _Log2("#~ WAIT_OBJECT_0 cstat.cbInQue=%d\n",cstat.cbInQue);//
+
+                        TInt min = Min((TInt)cstat.cbInQue, (TInt)KReadBufSize); 
+                        TInt i;
+						ReadFile(iCommPort,iInBuf,min,(LPDWORD)&i,&iReadOverLapped);
+						WaitForSingleObject(iReadOverLapped.hEvent,INFINITE);
+						GetOverlappedResult(iCommPort, &iReadOverLapped, (LPDWORD)&i, FALSE);
+                        __ASSERT_ALWAYS(i==min,Panic(EBadIOLen)); 
+
+                        cstat.cbInQue-=min;
+						i=0;
+						while (i<min)
+                            {
+
+                            if(i==(min-1) && !cstat.cbInQue)
+                                {
+                                //
+                                // Mark the final byte with the parity error
+                                //
+
+
+                                TInt temp=0;
+					            if (commErrors&CE_RXPARITY)
+						            temp|=KReceiveIsrParityError;
+					            if (commErrors&CE_FRAME)
+						            temp|=KReceiveIsrFrameError;
+					            if (commErrors&CE_OVERRUN)
+						            temp|=KReceiveIsrOverrunError;
+                                DoReceiveIsr(iInBuf[i++]|temp);
+                                }
+                            else
+							    DoReceiveIsr(iInBuf[i++]);
+                            }
+						}
+                    
+
+					}
+				}
+			if (iSignalStatus&(EV_DSR|EV_CTS|EV_RLSD))
+				DoStateIsr();
+			iSignalStatus=0;
+			WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
+			LeaveCritical();
+			break;
+		case WAIT_OBJECT_0+1:
+//
+// iCommThreadSemaphore has been signalled
+//
+			DriverCommand(iCommand);
+			break;
+		case WAIT_OBJECT_0+2:
+			//
+			//	Write completion
+			//
+			{
+			DWORD len=iWriteOverLapped.InternalHigh;
+//			GetOverlappedResult(iCommPort, &iWriteOverLapped, &len, FALSE);
+
+			EnterCritical();
+			WriteCompletion(this, 0, len);
+			LeaveCritical();
+			break;
+			}
+
+	    case WAIT_OBJECT_0+3:
+			//
+			// Read completion
+			//
+			{
+            ASSERT(iSocket);
+			EnterCritical();
+			if(iConfig->iHandshake & KConfigFreeRTS || iSignals & KSignalRTS)
+				{// Only read when RTS is freed or asserted
+
+                int num = recv(iSocket, (char*)iInBuf, 16, 0); // Only read 16 bytes at a go, to give LDD plenty of chance to flow off
+                
+                if(num == 0 ||  (num == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) || num < 0)
+					{
+					DoReceiveIsr(KReceiveIsrFrameError);
+					num = 0;
+					}
+
+				for(int i = 0; i<num; ++i)
+					{
+					DoReceiveIsr(iInBuf[i]);
+					}
+				// We'll automatically be re-signalled if there's more data waiting
+
+				iSignalStatus=0;
+	//			if(QueSocketRead() != KErrNone)
+	//				{
+	//				DoReceiveIsr(KReceiveIsrFrameError);
+	//				iNumInChars = 0;
+	//				}
+					
+				iReadPending = EFalse; // Make sure read is not queued
+				}
+			else // We cannot read at this time. 
+                {
+				// We have skipped the read, and the read event is reset at this point.
+				iReadPending = ETrue; // Queue the read event
+                _Log3("#~ ReadCompletion FC, iSignals=0x%x, iConfig->iHandshake=%d\n", iSignals, iConfig->iHandshake);
+                }
+			LeaveCritical();
+			break;
+			}		
+      
+
+        case WAIT_OBJECT_0+4:
+            //
+            //    Timer completion
+            //
+            {
+            Comm().TurnaroundStartDfcImplementation();
+            break;
+            }
+		
+		case WAIT_IO_COMPLETION:
+//
+// A read or write completion routine has been queued - why would we care?
+// Do nothing?
+            _Log("#~ WAIT_IO_COMPLETION\n");//
+
+		break;
+		
+		case WAIT_TIMEOUT: // Ignore the timeout.
+			// Just in case we timed out and no read is queued. 
+			// This is impossible, because we can time out only when a read is queued, 
+			// so we'll try to read rather than end up here. 
+			// This code is just in case there are further modifications to the event handling code.			
+			break;
+		
+		default:
+			MapWinError();
+			Panic(EWindowsUnexpectedError);
+			}
+		}
+	}
+
+void DCommWins::DriverCommand(TDriverCommand aCommand)
+//
+// Do a driver command - executed when the semaphore has been signalled in the comm port thread
+//
+	{
+	switch (aCommand)
+		{
+	case ESetBreak:
+		if(!UseSocket()) SetCommBreak(iCommPort);
+		break;
+	case EClearBreak:
+		if(!UseSocket()) ClearCommBreak(iCommPort);
+		break;
+	case ETransmit:
+		// Only Transmit one character to get the driver transmit cycle going
+		// otherwise we can empty the buffer and get double starts and re-write death
+		if (!iWritePending)
+			{
+			if(DoTransmitIsr(iNumOutChars))
+				iNumOutChars++;
+#if defined (_LOG_OUTPUT)
+			DWORD dummy;
+			WriteFile(iWritesHandle,iOutBuf,iNumOutChars,&dummy,NULL);
+#endif 
+			if (iNumOutChars>0)
+				{
+				iWritePending=ETrue;
+//				WriteFileEx(iCommPort,iOutBuf,iNumOutChars,&iWriteOverLapped,WriteComplete);
+				WriteFile(iCommPort,iOutBuf,iNumOutChars, NULL, &iWriteOverLapped);
+
+#if defined (_LOG_WRITES)
+					TBuf<0x40> buf;
+					DWORD dummy;
+					buf.Format(_L("writing %d\r\n"),iNumOutChars);
+					WriteFile(iLogFile,buf.PtrZ(),buf.Length(),&dummy,NULL);
+#endif
+
+				}
+			}
+		break;
+	case EStart:
+
+		if(UseSocket())
+		{
+			if(QueSocketRead() != KErrNone)
+				{// Couldn't que initial read :-(
+				__DEBUGGER();
+				}
+		}
+		else
+        {
+            DWORD err,res;
+		    COMSTAT s;
+		    if (iCommPort && ClearCommError(iCommPort,&err,&s)==FALSE)
+			    res=GetLastError();
+		    PurgeComm(iCommPort ,PURGE_RXCLEAR);
+		    iSignalStatus=0;
+		    WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
+        }
+
+	//	if (ReadFileEx(iCommPort,iInBuf,1,&iReadOverLapped,ReadComplete)==FALSE)
+	//		DWORD res=GetLastError();
+		break;
+	case EStop:
+		if(!UseSocket() && iNumOutChars)
+			{
+#if defined (_LOG_OUTPUT)
+			DWORD dummy;
+			WriteFile(iWritesHandle,iOutBuf,iNumOutChars,&dummy,NULL);
+#endif 
+            // Flush last write
+			if(iWritePending)
+			    {
+			    WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+			    FlushFileBuffers(iCommPort);
+                iWritePending=EFalse;
+				}
+			}
+		// Fall through
+	case EStopNoDrain:
+		if(UseSocket())
+			{
+			CancelIo(iCommPort); // cancels read & write (see below)
+			}
+		// Cancel any pending writes
+        if(iWritePending)
+		{
+			if(!UseSocket()) 
+            {
+                PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
+                WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+            }
+			iWritePending=EFalse;
+		}   
+
+		iStopping=ETrue;
+        if(iRunning)
+		{
+			if(!UseSocket())
+			{
+				SetCommMask(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR);
+				WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
+			}
+        }
+		break;
+	case EDie:	
+		SignalDriverThread();
+		ExitThread(1);
+		break;
+	case EConfigure:
+		DoConfigure();
+		break;
+	default:
+		// Panic(EUnknownCommand);
+		break;
+		}
+	iCommand=EInvalidCommand;
+	SignalDriverThread();
+	}
+
+TInt DCommWins::DoTransmitIsr(TInt anOffset)
+//
+// Call the transmit Isr in the LDD to get the next character
+//
+	{
+
+	TInt ret;
+	ret=Comm().TransmitIsr();
+	iOutBuf[anOffset]=(*(char *)&ret);
+#ifdef _DEBUG_DEVCOMM
+	iTxIntCount += (ret!=KTransmitIrqEmpty);
+#endif
+	return(ret!=KTransmitIrqEmpty);
+	}
+
+void DCommWins::DoReceiveIsr(TUint anCharAndMask)
+//
+// Call the Isr in the LDD to process this character
+//
+	{
+#ifdef _DEBUG_DEVCOMM
+	iRxIntCount++;
+	if (anCharAndMask & ~0xff)
+		iRxErrCount++;
+#endif
+	Comm().ReceiveIsr(anCharAndMask);
+	}
+
+void DCommWins::DoStateIsr()
+//
+// Call the Isr in the device to handle a line status change.
+//
+	{
+	Comm().StateIsr(Signals());
+	}
+
+void DCommWins::EnterCritical()
+//
+// Call the Isr in the device to handle a line status change.
+//
+	{
+	EnterCriticalSection(&iCriticalSection);
+	iIntRefCount++;
+	}
+
+void DCommWins::LeaveCritical()
+//
+// Call the Isr in the device to handle a line status change.
+//
+	{
+	--iIntRefCount;
+	LeaveCriticalSection(&iCriticalSection);
+	}
+ 
+void DCommWins::SetTimer(const TUint aTimeOut) 
+    { 
+    TInt timeout = aTimeOut; 
+    timeout *= 10; // to 100ns units 
+    timeout = -timeout; // make relative to current time 
+    iTimeOut.QuadPart = timeout; 
+    SetWaitableTimer(iWaitableTimer, &iTimeOut, 0, NULL, NULL, 0); 
+    } 
+ 
+void DCommWins::CancelTimer() 
+    { 
+    CancelWaitableTimer(iWaitableTimer); 
+    } 
+
+EXPORT_C DPhysicalDevice *CreatePhysicalDevice()
+//
+// Create a new physical device driver
+//
+	{
+
+	return(new DDriverComm);
+	}
+
+GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
+//
+// DLL entry point
+//
+	{
+
+	return(KErrNone);
+	}