emulator/emulatorbsp/specific/serialpdd.cpp
changeset 0 cec860690d41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emulator/emulatorbsp/specific/serialpdd.cpp	Tue Feb 02 01:39:10 2010 +0200
@@ -0,0 +1,1712 @@
+// 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
+// 
+//
+
+#include "winscomm.h"
+#include "nk_priv.h"
+#include "nk_plat.h"
+#include <emulator.h>
+
+#define WIN32_LEAN_AND_MEAN
+#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
+#include <windows.h>
+#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();
+	inline TBool LineFail();
+	
+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
+	TBool		iBreakDetected;
+	};
+
+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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	do
+		{
+		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)
+	{
+	DWORD err;
+	DWORD lastError = 0;
+	BOOL res;
+	COMSTAT s;
+	
+	do
+		{
+		ClearCommError(hFile, &err, &s);
+		res = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
+		if (!res)
+			lastError = GetLastError();
+		}
+	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
+
+	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)
+	{
+	TCommCaps3 capsBuf;
+	TCommCapsV03 &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;
+	c.iBreakSupported=ETrue;
+	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;
+	}
+
+void DCommWins::DoWriteComplete(TInt aErr)
+	{
+	iWritePending = 0;
+	iTransmitting = EFalse;
+	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)
+	{
+	iReadPending = 0;
+	iInDes.SetLength(aLength);
+	StartOfInterrupt();
+	iLdd->iRxCompleteDfc.Add();
+	EndOfInterrupt();
+	}
+
+
+
+void DCommWins::DoReadComplete(TInt aErr, TInt 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);
+			}
+		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);
+			}
+		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
+//
+	{
+
+	__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
+//
+	{
+	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"));
+	}
+#pragma warning( default : 4705 )
+
+TInt DCommWins::DoCreate(TInt aUnit,const TDesC8 * /*aInfo*/)
+//
+// Create the comms driver.
+//
+	{
+
+#if defined (__COM_ONE_ONLY__)
+	if (aUnit!=0)
+		return KErrNotSupported;
+#elif defined (__COM_TWO_ONLY__)
+	if (aUnit!=1)
+		return KErrNotSupported;
+#endif
+
+	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);
+			}
+		}
+	
+
+	//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);
+	
+	DCB dcb;
+	//set the dcb size
+	dcb.DCBlength = sizeof(dcb);
+	if (!GetCommStateP(iCommPort,&dcb))
+		return(Emulator::LastError());
+
+	EscapeCommFunctionP(iCommPort,0);
+
+//
+	if (!SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR|EV_RING))
+		return(Emulator::LastError());
+
+	if(!SetupComm(iCommPort,KDefaultWinNTReadBufSize,KDefaultWinNTWriteBufSize))
+		return(Emulator::LastError());
+
+	if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+		return(Emulator::LastError());
+
+	if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+		return(Emulator::LastError());
+
+//
+// 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 ((iThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)commThread,(void *)this, FALSE))==NULL)
+		return(Emulator::LastError());
+
+	SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
+	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()
+	{
+	if (iThread)
+		{
+		if (! iRunning)
+			{
+			__ASSERT_ALWAYS(
+				ResumeThread(iThread) != 0xffffffff,
+				Panic(EWindowsUnexpectedError)); 
+			}
+
+		iRunning=ETrue;
+		RunCommThread(EDie);
+		}
+
+	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();
+	}
+
+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))
+			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))
+			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)
+
+	{
+	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
+	{
+
+	ULONG signals=0;
+	GetCommModemStatusP(iCommPort,&signals);
+	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);
+		}
+	if (aSetMask&KSignalDTR)
+		{
+		iSignals|=KSignalDTR;
+		EscapeCommFunctionP(iCommPort,SETDTR);
+		}
+	if (aClearMask&KSignalRTS)
+		{
+		iSignals&=(~KSignalRTS);
+		EscapeCommFunctionP(iCommPort,CLRRTS);
+		}
+	if (aClearMask&KSignalDTR)
+		{
+		iSignals&=(~KSignalDTR);
+		EscapeCommFunctionP(iCommPort,CLRDTR);
+		}
+	}
+
+
+
+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
+//
+	{
+
+	DCB dcb = {0};
+	//set the dcb size
+	dcb.DCBlength = sizeof(dcb);
+	if (!GetCommStateP(iCommPort,&dcb))
+		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))
+		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
+		{
+		DWORD ret=WaitForMultipleObjectsEx(4,objects,FALSE,INFINITE,TRUE);
+		switch (ret)
+			{
+		case WAIT_OBJECT_0:
+			{
+			//			EnterCritical();
+
+			if (iDataAvailableNotification)
+				{
+				DataAvailableCompletion(this);
+				iDataAvailableNotification = EFalse;	//stop us repeatedly reporting it
+				}
+
+			// Detect breaks
+			if (iSignalStatus & EV_BREAK)
+				{
+				iBreakDetected=ETrue; // the read will complete with an error
+				}
+				
+			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
+//
+			DriverCommand(iCommand);
+			break;
+		case WAIT_OBJECT_0+2:
+			//
+			//	Write completion
+			//
+			{
+
+			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
+			//
+			{
+			DWORD len = 0;
+			TInt error = KErrNone;
+			if (!GetOverlappedResult(iCommPort, &iReadOverLapped, &len, FALSE))
+				{
+				// May have a break already detected to report
+				if (iBreakDetected)
+					{
+					error=KErrCommsBreak;
+					iBreakDetected=EFalse;
+					}
+				else
+					error = Emulator::LastError();
+				}
+			else
+				iBreakDetected=EFalse; // No error, so any breaks have finished
+			
+			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:
+			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
+//
+	{
+	switch (aCommand)
+		{
+	case ESetBreak:
+		FlushFileBuffers(iCommPort);
+		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);
+			iWritePending = ETransmit;
+			iTransmitting= ETrue;
+			}
+		break;
+
+	case EStart:
+		{
+		iSignalStatus=0;
+		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 EStop:
+        // Flush last write
+		if(iWritePending == ETransmit)
+			{
+			WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+			FlushFileBuffers(iCommPort);
+			}
+        iWritePending=0;
+        iTransmitting=EFalse;
+		// Fall through
+	case EStopNoDrain:
+		// Cancel any pending writes
+        if(iWritePending == ETransmit)
+		    {
+			PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
+            WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+		    }   
+        iWritePending=0;
+		iTransmitting=EFalse;
+		iStopping=ETrue;
+        if(iRunning)
+            {
+            SetCommMaskP(iCommPort,EV_BREAK|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;
+	
+	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);
+				}
+			else
+				{
+				ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
+				}
+
+			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);
+				}
+			else
+				{
+				ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
+				}
+
+			iReadPending = EReceiveOneOrMore;
+			}
+		break;
+
+	case EReceiveCancel:
+		if (iReadPending)
+			PurgeComm(iCommPort, PURGE_RXABORT);
+		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;
+	}
+
+inline TBool DCommWins::LineFail()
+	{
+	return iLineFail;
+	}
+
+
+
+DECLARE_STANDARD_PDD()
+	{
+	return new DDriverComm;
+	}
+