emulator/emulatorbsp/specific/serialpdd.cpp
changeset 0 cec860690d41
equal deleted inserted replaced
-1:000000000000 0:cec860690d41
       
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // wins/specific/serialpdd.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "winscomm.h"
       
    19 #include "nk_priv.h"
       
    20 #include "nk_plat.h"
       
    21 #include <emulator.h>
       
    22 
       
    23 #define WIN32_LEAN_AND_MEAN
       
    24 #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
       
    25 #include <windows.h>
       
    26 #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
       
    27 
       
    28 #ifdef FAULT
       
    29 #undef FAULT
       
    30 #endif
       
    31 #define FAULT() Kern::Fault(__FILE__,__LINE__)
       
    32 
       
    33 _LIT(KComName, "\\\\.\\com");
       
    34 
       
    35 // needs ldd version..
       
    36 const TInt KMinimumLddMajorVersion=1;
       
    37 const TInt KMinimumLddMinorVersion=1;
       
    38 const TInt KMinimumLddBuild=1;		
       
    39 
       
    40 //used for the read and write buffers in the driver.
       
    41 //large buffer reserved so any transfer to/from the client can fit into a driver buffer
       
    42 const TInt KSerialBufferMaxSize = 0x800000;
       
    43 const TInt KSerialBufferInitialSize = 0x10000;
       
    44 const TInt KSerialBufferIncrementSize = 0x1000;	//granularity.  must be power of 2	
       
    45 
       
    46 
       
    47 const DWORD KReadOneOrMoreTimeout = MAXDWORD-1;	//milliseconds
       
    48 
       
    49 
       
    50 //buffer sizes passed to NT for setting its own driver buffer sizes
       
    51 const TInt KDefaultWinNTReadBufSize = 1024;
       
    52 const TInt KDefaultWinNTWriteBufSize = 1024;
       
    53 
       
    54 static DWORD dummyLen=0;
       
    55 
       
    56 enum TDCommWinsFault 
       
    57 	{
       
    58 	EWindowsUnexpectedError,
       
    59 	EUnknownCommand,
       
    60 	EBadIOLen,
       
    61 	EEofOnSerial,
       
    62 	EWriteEarlyCompletion,
       
    63 	ELineErrorNotReported,
       
    64 	ESerialBufferTooBig,
       
    65 	EReadLength,
       
    66 	};
       
    67 
       
    68 
       
    69 class DDriverComm : public DPhysicalDevice
       
    70 	{
       
    71 public:
       
    72 	DDriverComm();
       
    73 	virtual TInt Install();
       
    74 	virtual TInt Remove();
       
    75 	virtual void GetCaps(TDes8 &aDes) const;
       
    76 	virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
       
    77 	virtual TInt Validate(TInt aUnit, const TDesC8* aInfo, const TVersion &aVer);
       
    78 	};
       
    79 
       
    80 
       
    81 class DCommWins : public DComm
       
    82 	{
       
    83 public:
       
    84 	enum TDriverCommand {ESetBreak=1,EClearBreak,ETransmit,ETransmit0,
       
    85 						EGetSignals,ESetSignals,EConfigure,
       
    86 						EStop,EStopNoDrain,EStart,EDie,	ETransmitCancel,
       
    87 						EReceive, EReceiveOneOrMore, EReceiveCancel,ENotifyDataAvailable,
       
    88 						ENotifySignals, EInvalidCommand};
       
    89 public:
       
    90 	DCommWins();
       
    91 	~DCommWins();
       
    92 	virtual TInt Start();
       
    93 	virtual void Stop(TStopMode aMode);
       
    94 	virtual void Break(TBool aState);
       
    95 	virtual void Write(DThread* aThread, TAny *aTxDes, TInt aLength);
       
    96 	virtual void Read(DThread* aThread, TAny *aTxDes, TInt aLength);
       
    97 	virtual void NotifySignals(DThread* aThread, TInt aMask);
       
    98 	virtual void NotifyDataAvailable();
       
    99 	virtual TUint Signals() const;
       
   100 	virtual void SetSignals(TUint aSetMask,TUint aClearMask);
       
   101 	virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const;
       
   102 	virtual void Configure(TCommConfigV01 &aConfig);
       
   103 	virtual void Caps(TDes8 &aCaps) const;
       
   104 	virtual void CheckConfig(TCommConfigV01& aConfig);
       
   105 	virtual TDfcQue* DfcQ(TInt aUnit);
       
   106 
       
   107 	inline void CheckTxBuffer();
       
   108 	inline TBool Transmitting();
       
   109 	virtual TInt RxCount();
       
   110 	virtual void ResetBuffers(TBool);
       
   111 	virtual TInt SetRxBufferSize(TInt aSize);
       
   112 	virtual TInt RxBufferSize();
       
   113 	virtual TDes8* RxBuffer();
       
   114 	virtual void DoConfigure();
       
   115 	virtual TBool AreAnyPending();
       
   116 	virtual void ReadCancel();
       
   117 	virtual void WriteCancel();
       
   118 	virtual void SignalChangeCancel();
       
   119 	TInt DoCreate(TInt aUnit,const TDesC8 *aInfo);
       
   120 	void WaitForEvent();
       
   121 	void DriverCommand(TDriverCommand aCommand);
       
   122 	void DoWriteComplete(TInt aErr);
       
   123 	void DoReadComplete(TInt aErr, TInt aBytes);
       
   124 	void DoSignalCompletion(TInt aError, TUint changed, TUint aValues);
       
   125 	void DoDataAvailableCompletion();
       
   126 	void RunCommThread(TDriverCommand aCommand);
       
   127 	inline void SignalDriverThread();
       
   128 	inline TBool LineFail();
       
   129 	
       
   130 private:
       
   131 	void ReleaseBuffers();
       
   132 	void ReSizeBuffer(TUint8*& aBuf, TInt& iBufLen, TPtr8& aDes, const TInt aNewLen);
       
   133 	TBool IsATerminator(TText8 aChar);
       
   134 	void CompleteRead(TInt aLength);
       
   135 	void DataAvailableNotificationCancel();
       
   136 
       
   137 
       
   138 private:
       
   139 	TInt iWritePending;
       
   140 	TInt iReadPending;
       
   141 	TBool iStopping;
       
   142 	TBool iRunning;
       
   143 	TDriverCommand iCommand;
       
   144 	TCommConfigV01 *iConfig;
       
   145 	TUint iSignals;
       
   146 	TUint iFailSignals;
       
   147 	TUint iSavedSignals;
       
   148 	TBool iLineFail;
       
   149 	TBool iRXLineFail;
       
   150 	TBool iTXLineFail;
       
   151 
       
   152 	TUint8 * iInBufPtr;		//input buffer used by driver.
       
   153 	TInt iInBufLength;
       
   154 	TPtr8 iInDes;
       
   155 
       
   156 	TInt iReadSoFar;
       
   157 	TBool iTerminatedRead;	//true if we are reading with 1 or more terminating characters
       
   158 
       
   159 	TUint8 * iOutBufPtr;
       
   160 	TInt iOutBufLength;
       
   161 	TPtr8 iOutDes;
       
   162 
       
   163 	TInt iRxBufferSize;		//size of receivebuffer passed to windows & set by calls to SetReceiveBufferSize 
       
   164 							//used to determine xon and xoff levels
       
   165 	TUint iSignalsRequested;  //mask of signals we are waiting for
       
   166 	TUint iSignalsWanted;		//mask we are asked to check 
       
   167 	TBool iDataAvailableNotification;
       
   168 	HANDLE iThread;
       
   169 	HANDLE iCommThreadSem;
       
   170 	HANDLE iDriverThreadSem;
       
   171 	HANDLE iCommPort;
       
   172 	DWORD iThreadID;
       
   173 	DWORD iSignalStatus;
       
   174 	OVERLAPPED iReadOverLapped;
       
   175 	OVERLAPPED iWriteOverLapped;
       
   176 	OVERLAPPED iSignalOverLapped;
       
   177 
       
   178 	TInt iClientReadLength;		//how much data the client has requested in a read
       
   179 	TBool		iBreakDetected;
       
   180 	};
       
   181 
       
   182 void Panic(TDCommWinsFault aFault)
       
   183 //
       
   184 // Panic the driver 
       
   185 //
       
   186 	{
       
   187 	Kern::PanicCurrentThread(_L("DCommWins"), aFault);
       
   188 	}
       
   189 
       
   190 
       
   191 TUint commThread(DCommWins *comm)
       
   192 //
       
   193 // Comm thread entry point
       
   194 //
       
   195 	{
       
   196 
       
   197 	comm->WaitForEvent();
       
   198 	return 0;
       
   199 	}
       
   200 
       
   201 VOID WINAPI WriteCompletion(DCommWins *aDrv, DWORD aErr,DWORD /*numBytes*/)
       
   202 	{
       
   203 
       
   204 	aDrv->DoWriteComplete(aErr);
       
   205 	}
       
   206 
       
   207 
       
   208 VOID WINAPI ReadCompletion(DCommWins *aDrv, DWORD aErr,DWORD numBytes)
       
   209 	{
       
   210 
       
   211 	aDrv->DoReadComplete(aErr, numBytes);
       
   212 	}
       
   213 
       
   214 VOID WINAPI SignalCompletion(DCommWins *aDrv, TInt aError, TUint aChanged, TUint aValues)
       
   215 	{
       
   216 	aDrv->DoSignalCompletion(aError, aChanged, aValues);
       
   217 	}
       
   218 
       
   219 VOID WINAPI DataAvailableCompletion(DCommWins *aDrv)
       
   220 	{
       
   221 	aDrv->DoDataAvailableCompletion();
       
   222 	}
       
   223 
       
   224 
       
   225 
       
   226 BOOL WINAPI EscapeCommFunctionP(HANDLE hFile,DWORD dwFunc)
       
   227 	{
       
   228 	DWORD err;
       
   229 	DWORD lastError = 0;
       
   230 	BOOL res;
       
   231 	COMSTAT s;
       
   232 	
       
   233 	do
       
   234 		{
       
   235 		ClearCommError(hFile, &err, &s);
       
   236 		res = EscapeCommFunction(hFile,dwFunc);
       
   237 		if(!res)
       
   238 			lastError = GetLastError();
       
   239 		}
       
   240 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   241 
       
   242 	return(res);
       
   243 	}
       
   244 
       
   245 
       
   246 BOOL WINAPI GetCommModemStatusP(HANDLE hFile,LPDWORD lpModemStat)
       
   247 	{
       
   248 	DWORD err;
       
   249 	DWORD lastError = 0;
       
   250 	BOOL res;
       
   251 	COMSTAT s;
       
   252 	
       
   253 	do
       
   254 		{
       
   255 		ClearCommError(hFile, &err, &s);
       
   256 		res = GetCommModemStatus(hFile,lpModemStat);
       
   257 		if(!res)
       
   258 			lastError  = GetLastError();
       
   259 		}
       
   260 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   261 
       
   262 	return(res);
       
   263 	}
       
   264 
       
   265 
       
   266 BOOL WINAPI GetCommStateP(HANDLE hFile,LPDCB lpDCB)
       
   267 	{
       
   268 	DWORD err;
       
   269 	DWORD lastError = 0;
       
   270 	BOOL res;
       
   271 	COMSTAT s;
       
   272 	
       
   273 	do
       
   274 		{
       
   275 		ClearCommError(hFile,&err,&s);
       
   276 		res = GetCommState(hFile,lpDCB);
       
   277 		if (!res)
       
   278 			lastError = GetLastError();
       
   279 		}
       
   280 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   281 
       
   282 	return(res);
       
   283 	}
       
   284 
       
   285 BOOL WINAPI SetCommStateP(HANDLE hFile,LPDCB lpDCB)
       
   286 	{
       
   287 	DWORD err;
       
   288 	DWORD lastError = 0;
       
   289 	BOOL res;
       
   290 	COMSTAT s;
       
   291 	
       
   292 	do
       
   293 		{
       
   294 		ClearCommError(hFile, &err, &s);
       
   295 		res = SetCommState(hFile, lpDCB);
       
   296 		if (!res)
       
   297 			lastError = GetLastError();
       
   298 		}
       
   299 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   300 
       
   301 	return(res);
       
   302 	}
       
   303 
       
   304 BOOL WINAPI SetCommMaskP(HANDLE hFile,DWORD dwEvtMask)
       
   305 	{
       
   306 	DWORD err;
       
   307 	DWORD lastError = 0;
       
   308 	BOOL res;
       
   309 	COMSTAT s;
       
   310 	
       
   311 	do
       
   312 		{
       
   313 		ClearCommError(hFile, &err, &s);
       
   314 		res = SetCommMask(hFile, dwEvtMask);
       
   315 		if (!res)
       
   316 			lastError = GetLastError();
       
   317 		}
       
   318 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   319 
       
   320 	return(res);
       
   321 	}
       
   322 
       
   323 BOOL WINAPI WriteFileP(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)
       
   324 	{
       
   325 	DWORD err;
       
   326 	DWORD lastError = 0;
       
   327 	BOOL res;
       
   328 	COMSTAT s;
       
   329 	
       
   330 	do
       
   331 		{
       
   332 		ClearCommError(hFile, &err, &s);
       
   333 		res = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
       
   334 		if (!res)
       
   335 			lastError = GetLastError();
       
   336 		}
       
   337 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   338 
       
   339 	return(res);
       
   340 	}
       
   341 
       
   342 BOOL WINAPI ReadFileP(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
       
   343 	{
       
   344 	DWORD err;
       
   345 	DWORD lastError = 0;
       
   346 	BOOL res;
       
   347 	COMSTAT s;
       
   348 	
       
   349 	do
       
   350 		{
       
   351 		ClearCommError(hFile, &err, &s);
       
   352 		res = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
       
   353 		if (!res)
       
   354 			lastError = GetLastError();
       
   355 		}
       
   356 	while((!res) && (lastError == ERROR_OPERATION_ABORTED));
       
   357 
       
   358 	return(res);
       
   359 	}
       
   360 
       
   361 
       
   362 
       
   363 
       
   364 DDriverComm::DDriverComm()
       
   365 	{
       
   366 #if defined (__COM_ONE_ONLY__)
       
   367 	iUnitsMask=0x1; // Support units 0
       
   368 #elif defined (__COM_TWO_ONLY__)
       
   369 	iUnitsMask=0x2; // Support units 1
       
   370 #else
       
   371 	iUnitsMask=0x3ff; // Support units 0 to 9
       
   372 #endif
       
   373 
       
   374 	iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
       
   375 	}
       
   376 
       
   377 TInt DDriverComm::Install()
       
   378 	{
       
   379 #if defined (__COM_ONE_ONLY__)
       
   380 	TPtrC buf=_L("Comm.Wins1");
       
   381 	return(SetName(&buf));
       
   382 #elif defined (__COM_TWO_ONLY__)
       
   383 	TPtrC buf=_L("Comm.Wins2");
       
   384 	return(SetName(&buf));
       
   385 #else
       
   386 	TPtrC buf=_L("Comm.Wins");
       
   387 	return(SetName(&buf));
       
   388 #endif
       
   389 	}
       
   390 
       
   391 TInt DDriverComm::Remove()
       
   392 	{
       
   393 	return(KErrNone);
       
   394 	}
       
   395 
       
   396 
       
   397 TInt DDriverComm::Validate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
       
   398 //
       
   399 //	Validate the requested configuration
       
   400 //
       
   401 	{
       
   402 	if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
       
   403 		return KErrNotSupported;
       
   404 #if defined (__COM_ONE_ONLY__)
       
   405 	if (aUnit!=0)
       
   406 		return KErrNotSupported;
       
   407 #elif defined (__COM_TWO_ONLY__)
       
   408 	if (aUnit!=1)
       
   409 		return KErrNotSupported;
       
   410 #endif
       
   411 	// leave Unit check to CreateFile
       
   412 	return KErrNone;
       
   413 	}
       
   414 
       
   415 
       
   416 void GetWinsCommsCaps(TDes8 &aCaps)
       
   417 	{
       
   418 	TCommCaps3 capsBuf;
       
   419 	TCommCapsV03 &c=capsBuf();
       
   420 //
       
   421 // All rates except 50,2000, 3600 and special
       
   422 //
       
   423 	c.iRate=KCapsBps75|KCapsBps110|KCapsBps134|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps1800|KCapsBps2400|KCapsBps4800|KCapsBps7200|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200;
       
   424 
       
   425 	c.iDataBits=0xf; // All data sizes
       
   426 	c.iStopBits=0x3; // 1 and 2 stop bits
       
   427 	c.iParity=0x7; // None, Even and Odd
       
   428 	c.iHandshake = 0x3BF;	//all except KConfigObeyDCD
       
   429 	c.iSignals=0x3f; // All signals
       
   430 	c.iSIR=0;//No Ir
       
   431 	c.iNotificationCaps=KNotifySignalsChangeSupported|KNotifyDataAvailableSupported;
       
   432 	c.iRoleCaps=0;
       
   433 	c.iFlowControlCaps=0;
       
   434 	c.iBreakSupported=ETrue;
       
   435 	aCaps.FillZ(aCaps.MaxLength());
       
   436 	aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
       
   437 	}
       
   438 
       
   439 void DDriverComm::GetCaps(TDes8 &aDes) const
       
   440 	{
       
   441 	GetWinsCommsCaps(aDes);
       
   442 	}
       
   443 
       
   444 TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit,const TDesC8* aInfo,const TVersion& aVer)
       
   445 	{
       
   446 
       
   447 	if (!Kern::QueryVersionSupported(iVersion,aVer))
       
   448 		return KErrNotSupported;
       
   449 
       
   450 	DCommWins *pD= new DCommWins;
       
   451 	if (!pD) return KErrNoMemory;
       
   452 
       
   453 	TInt ret=pD->DoCreate(aUnit,aInfo);
       
   454 
       
   455 	if (ret!=KErrNone)
       
   456 	{
       
   457 		delete pD;
       
   458 		return ret;
       
   459 	}
       
   460 	
       
   461 	aChannel = pD;
       
   462 
       
   463 	return KErrNone;
       
   464 	}
       
   465 
       
   466 void DCommWins::DoWriteComplete(TInt aErr)
       
   467 	{
       
   468 	iWritePending = 0;
       
   469 	iTransmitting = EFalse;
       
   470 	StartOfInterrupt();
       
   471 	iLdd->iTxError = aErr;
       
   472 	iLdd->iTxCompleteDfc.Add();
       
   473 	EndOfInterrupt();
       
   474 	}
       
   475 
       
   476 
       
   477 
       
   478 void DCommWins::DoSignalCompletion(TInt aError, TUint aChanged, TUint aValues)
       
   479 	{
       
   480 	//aValues contains the signal values.  EPOC constants
       
   481 	//aChanged contains the signals which have changed
       
   482 	//we return the signal values
       
   483 	TUint res = aValues & iSignalsWanted;
       
   484 	res |= (aChanged << 12);
       
   485 	
       
   486 	iLdd->iSignalResult = res;
       
   487 	iLdd->iSignalError = aError;
       
   488 	StartOfInterrupt();
       
   489 	iLdd->iSigNotifyDfc.Add();
       
   490 	EndOfInterrupt();
       
   491 	}
       
   492 
       
   493 void DCommWins::DoDataAvailableCompletion()
       
   494 	{
       
   495 	StartOfInterrupt();
       
   496 	iLdd->iRxDataAvailableDfc.Add();
       
   497 	EndOfInterrupt();
       
   498 	}
       
   499 
       
   500 
       
   501 
       
   502 void DCommWins::CompleteRead(TInt aLength)
       
   503 	{
       
   504 	iReadPending = 0;
       
   505 	iInDes.SetLength(aLength);
       
   506 	StartOfInterrupt();
       
   507 	iLdd->iRxCompleteDfc.Add();
       
   508 	EndOfInterrupt();
       
   509 	}
       
   510 
       
   511 
       
   512 
       
   513 void DCommWins::DoReadComplete(TInt aErr, TInt aBytes)
       
   514 	{
       
   515 	iLdd->iRxError = aErr;
       
   516 	//write back the length and the data
       
   517 	//process for any terminating characters.
       
   518 	//win32 only does binary reads and ignores the eofchar, so terminated reads
       
   519 	//require reading one char at a time
       
   520 	if (iTerminatedRead && !aErr)
       
   521 		{
       
   522 		__NK_ASSERT_ALWAYS(aBytes <= 1);
       
   523 		if (aBytes == 0)
       
   524 			{
       
   525 			// not sure why we get this somtimes, but handle it anyway : read another character
       
   526 			ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped);
       
   527 			}
       
   528 		else if (++iReadSoFar == iClientReadLength)	//see if we have read enough characters into the buffer
       
   529 			{
       
   530 			//got them all so complete it
       
   531 			CompleteRead(iReadSoFar);
       
   532 			}
       
   533 		else if (IsATerminator(iInBufPtr[iReadSoFar-1]))	//see if the char just read was the terminator
       
   534 			{
       
   535 			//it's a terminated read and we've found one of the terminbators
       
   536 			CompleteRead(iReadSoFar);
       
   537 			}
       
   538 		else if (iReadPending == EReceive)
       
   539 			{
       
   540 			//read another character
       
   541 			ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped);
       
   542 			}
       
   543 		else
       
   544 			{
       
   545 			//it's a receive 1 or more with terminators, we've got 1 so that'll do
       
   546 			CompleteRead(iReadSoFar);
       
   547 			}
       
   548 		}
       
   549 	else
       
   550 		{
       
   551 		CompleteRead(aBytes);
       
   552 		}
       
   553 	}
       
   554 
       
   555 
       
   556 
       
   557 
       
   558 void DCommWins::RunCommThread(TDriverCommand aCommand)
       
   559 //
       
   560 // Wake up the comms thread
       
   561 //
       
   562 	{
       
   563 
       
   564 	__ASSERT_DEBUG(aCommand!=EInvalidCommand,Panic(EUnknownCommand));
       
   565 	iCommand=aCommand;
       
   566 //
       
   567 // Are we about to go re-entrant?
       
   568 //
       
   569 	if(GetCurrentThreadId()==iThreadID)
       
   570 		{
       
   571 		DriverCommand(aCommand);
       
   572 		WaitForSingleObject(iDriverThreadSem,INFINITE);
       
   573 		}
       
   574 	else
       
   575 		{
       
   576 		Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
       
   577 		if (ReleaseSemaphore(iCommThreadSem,1,NULL)==FALSE)
       
   578 			{
       
   579 			DWORD ret=GetLastError();
       
   580 			ret=ret;
       
   581 			Panic(EWindowsUnexpectedError);
       
   582 			}
       
   583 		WaitForSingleObject(iDriverThreadSem,INFINITE);
       
   584 		}
       
   585 	}
       
   586 
       
   587 inline void DCommWins::SignalDriverThread()
       
   588 //
       
   589 // Wake up the comms thread
       
   590 //
       
   591 	{
       
   592 	Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
       
   593 	if (ReleaseSemaphore(iDriverThreadSem,1,NULL)==FALSE)
       
   594 		{
       
   595 		DWORD ret=GetLastError();
       
   596 		ret=ret;
       
   597 		Panic(EWindowsUnexpectedError);
       
   598 		}
       
   599 	}
       
   600 
       
   601 
       
   602 
       
   603 //
       
   604 #pragma warning( disable : 4705 )	// statement has no effect
       
   605 DCommWins::DCommWins() :  iOutDes(0,0), iInDes(0,0), iRxBufferSize(KDefaultWinNTReadBufSize), iSignalsRequested(0)
       
   606 	{
       
   607 	__DECLARE_NAME(_S("DCommWins"));
       
   608 	}
       
   609 #pragma warning( default : 4705 )
       
   610 
       
   611 TInt DCommWins::DoCreate(TInt aUnit,const TDesC8 * /*aInfo*/)
       
   612 //
       
   613 // Create the comms driver.
       
   614 //
       
   615 	{
       
   616 
       
   617 #if defined (__COM_ONE_ONLY__)
       
   618 	if (aUnit!=0)
       
   619 		return KErrNotSupported;
       
   620 #elif defined (__COM_TWO_ONLY__)
       
   621 	if (aUnit!=1)
       
   622 		return KErrNotSupported;
       
   623 #endif
       
   624 
       
   625 	TBuf8<0x10> n;
       
   626 	n.Append(KComName);
       
   627 	n.AppendNum(aUnit+1);
       
   628 	n.Append('\0');
       
   629 
       
   630 	iCommPort=CreateFileA((LPCSTR)n.Ptr(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
       
   631 	if (iCommPort==INVALID_HANDLE_VALUE)	
       
   632 		{	
       
   633 	//	Reused code from Emulator::LastError() rather than adding an extra case 
       
   634 	//	to Emulator::LastError() because mapping KErrNotSupported to the returned
       
   635 	//	FILE_NOT_FOUND is non-intuitive and special to this case only
       
   636 		DWORD winErr=GetLastError();
       
   637 		switch (winErr)
       
   638 			{
       
   639 			case ERROR_INVALID_USER_BUFFER:
       
   640 			case ERROR_NOT_ENOUGH_MEMORY:
       
   641 			case ERROR_INSUFFICIENT_BUFFER:
       
   642 				return(KErrNoMemory);
       
   643 			case ERROR_ACCESS_DENIED:
       
   644 				return(KErrAccessDenied);
       
   645 			case ERROR_FILE_NOT_FOUND:		//	Reflects value returned by
       
   646 				return(KErrNotSupported);	//	corresponding MARM Pdd  
       
   647 			case ERROR_NOT_SUPPORTED:
       
   648 				return(KErrNotSupported);
       
   649 			default:
       
   650 				return(KErrGeneral);
       
   651 			}
       
   652 		}
       
   653 	
       
   654 
       
   655 	//create the buffers.
       
   656 	//the buffers need to be as big as the client will ever use.  8mb reserved, but commit less
       
   657 	iInBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
       
   658 	if (!iInBufPtr)
       
   659 		return(Emulator::LastError());
       
   660 
       
   661 	//commit the first bit of the buffer
       
   662 	if (!VirtualAlloc(iInBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
       
   663 		return(Emulator::LastError());
       
   664 
       
   665 	iInBufLength = KSerialBufferInitialSize;
       
   666 	iInDes.Set(iInBufPtr, 0, iInBufLength);
       
   667 
       
   668 	//reserve address space for the output buffer
       
   669 	iOutBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
       
   670 	if (!iOutBufPtr)
       
   671 		return(Emulator::LastError());
       
   672 
       
   673 	//commit a smaller region of it
       
   674 	if (!VirtualAlloc(iOutBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
       
   675 		return(Emulator::LastError());
       
   676 
       
   677 	iOutBufLength = KSerialBufferInitialSize;
       
   678 	iOutDes.Set(iOutBufPtr, 0, iOutBufLength);
       
   679 	
       
   680 	DCB dcb;
       
   681 	//set the dcb size
       
   682 	dcb.DCBlength = sizeof(dcb);
       
   683 	if (!GetCommStateP(iCommPort,&dcb))
       
   684 		return(Emulator::LastError());
       
   685 
       
   686 	EscapeCommFunctionP(iCommPort,0);
       
   687 
       
   688 //
       
   689 	if (!SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR|EV_RING))
       
   690 		return(Emulator::LastError());
       
   691 
       
   692 	if(!SetupComm(iCommPort,KDefaultWinNTReadBufSize,KDefaultWinNTWriteBufSize))
       
   693 		return(Emulator::LastError());
       
   694 
       
   695 	if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
       
   696 		return(Emulator::LastError());
       
   697 
       
   698 	if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
       
   699 		return(Emulator::LastError());
       
   700 
       
   701 //
       
   702 // The serial port seems to open with the error condition set
       
   703 //
       
   704 
       
   705 	DWORD err,res;
       
   706 	COMSTAT s;
       
   707 	if (ClearCommError(iCommPort,&err,&s)==FALSE)
       
   708 		res=GetLastError();
       
   709 
       
   710 	if ((iThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)commThread,(void *)this, FALSE))==NULL)
       
   711 		return(Emulator::LastError());
       
   712 
       
   713 	SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
       
   714 	return(KErrNone);
       
   715 	}
       
   716 
       
   717 
       
   718 	
       
   719 void DCommWins::ReleaseBuffers()
       
   720 	{
       
   721 	if (iInBufPtr)
       
   722 		{
       
   723 		//decommit the buffer
       
   724 		VirtualFree(iInBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
       
   725 		//and release the region
       
   726 		VirtualFree(iInBufPtr, NULL, MEM_RELEASE);
       
   727 		iInBufPtr = NULL;
       
   728 		}
       
   729 	if (iOutBufPtr)
       
   730 		{
       
   731 		VirtualFree(iOutBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
       
   732 		VirtualFree(iOutBufPtr, NULL, MEM_RELEASE);
       
   733 		iOutBufPtr = NULL;
       
   734 		}
       
   735 	}
       
   736 	
       
   737 
       
   738 DCommWins::~DCommWins()
       
   739 	{
       
   740 	if (iThread)
       
   741 		{
       
   742 		if (! iRunning)
       
   743 			{
       
   744 			__ASSERT_ALWAYS(
       
   745 				ResumeThread(iThread) != 0xffffffff,
       
   746 				Panic(EWindowsUnexpectedError)); 
       
   747 			}
       
   748 
       
   749 		iRunning=ETrue;
       
   750 		RunCommThread(EDie);
       
   751 		}
       
   752 
       
   753 	if (iCommPort)
       
   754 		CloseHandle(iCommPort);
       
   755 
       
   756 	if (iDriverThreadSem)
       
   757 		CloseHandle(iDriverThreadSem);
       
   758 
       
   759 	if (iCommThreadSem)
       
   760 		CloseHandle(iCommThreadSem);
       
   761 
       
   762 	if (iReadOverLapped.hEvent)
       
   763 		CloseHandle(iReadOverLapped.hEvent);
       
   764 
       
   765 	if (iWriteOverLapped.hEvent)
       
   766 		CloseHandle(iWriteOverLapped.hEvent);
       
   767 
       
   768 	if (iSignalOverLapped.hEvent)
       
   769 		CloseHandle(iSignalOverLapped.hEvent);
       
   770 
       
   771 	if (iThread)
       
   772 		CloseHandle(iThread);
       
   773 
       
   774 	//free up the memory
       
   775 	ReleaseBuffers();
       
   776 	}
       
   777 
       
   778 TInt DCommWins::Start()
       
   779 	{
       
   780 
       
   781 	__ASSERT_ALWAYS(ResumeThread(iThread)!=0xffffffff,Panic(EWindowsUnexpectedError));
       
   782 	iRunning=ETrue;
       
   783 	RunCommThread(EStart);
       
   784 	return(KErrNone);
       
   785 	}
       
   786 
       
   787 void DCommWins::Stop(TStopMode aMode)
       
   788 	{
       
   789 
       
   790 	RunCommThread((aMode==EStopEmergency) ? EStopNoDrain : EStop);
       
   791 	SuspendThread(iThread);
       
   792 	iRunning=EFalse;
       
   793 	}
       
   794 
       
   795 void DCommWins::Break(TBool aState)
       
   796 //
       
   797 // Assert a break signal
       
   798 //
       
   799 	{
       
   800 	if (aState)
       
   801 		RunCommThread(ESetBreak);
       
   802 	else
       
   803 		RunCommThread(EClearBreak);
       
   804 	}
       
   805 
       
   806 
       
   807 
       
   808 TInt DCommWins::RxCount()
       
   809 	{
       
   810 	DWORD err =0;
       
   811 	COMSTAT stat;
       
   812 	if (ClearCommError(iCommPort,&err, &stat))
       
   813 		return stat.cbInQue;
       
   814 	else
       
   815 		return Emulator::LastError();
       
   816 	}
       
   817 
       
   818 
       
   819 void DCommWins::ResetBuffers(TBool aTx)
       
   820 	{
       
   821 	PurgeComm(iCommPort, PURGE_RXCLEAR | (aTx ? PURGE_TXCLEAR : 0));
       
   822 	}
       
   823 
       
   824 
       
   825 TBool DCommWins::AreAnyPending()
       
   826 	{
       
   827 	return (iReadPending != 0) || (iWritePending != 0);
       
   828 	}
       
   829 
       
   830 
       
   831 void DCommWins::WriteCancel()
       
   832 	{
       
   833 	DriverCommand(ETransmitCancel);
       
   834 	}
       
   835 
       
   836 
       
   837 void DCommWins::ReadCancel()
       
   838 	{
       
   839 	DriverCommand(EReceiveCancel);
       
   840 	}
       
   841 
       
   842 void DCommWins::SignalChangeCancel()
       
   843 	{
       
   844 	if (iSignalsRequested)
       
   845 		{
       
   846 		iSignalsRequested = 0;
       
   847 		}
       
   848 
       
   849 	}
       
   850 
       
   851 void DCommWins::DataAvailableNotificationCancel()
       
   852 	{
       
   853 	if (iDataAvailableNotification)
       
   854 		{
       
   855 		iDataAvailableNotification = EFalse;
       
   856 		iLdd->iRxDAError = KErrCancel;
       
   857 		iLdd->iRxDataAvailableDfc.Enque();
       
   858 		}
       
   859 	}
       
   860 
       
   861 TDes8* DCommWins::RxBuffer()
       
   862 	{
       
   863 	return &iInDes;
       
   864 	}
       
   865 
       
   866 TInt DCommWins::SetRxBufferSize(TInt aSize)
       
   867 	{
       
   868 	aSize += aSize&1;	//round up to multiple of 2 bytes as windows complains if odd
       
   869 	TInt ret = SetupComm(iCommPort, aSize, KDefaultWinNTWriteBufSize);
       
   870 	if (ret)
       
   871 		{
       
   872 		iRxBufferSize = aSize;
       
   873 		
       
   874 		DCB dcb = {0};
       
   875 		dcb.DCBlength = sizeof(dcb);
       
   876 		
       
   877 		if (!GetCommStateP(iCommPort,&dcb))
       
   878 			return Emulator::LastError();
       
   879 
       
   880 		//use rx buffer size to configure xon/xoff limits
       
   881 		dcb.XoffLim = (WORD)(iRxBufferSize / 4);		//25%
       
   882 		if (iConfig->iParityError & KConfigXonXoffDebug)
       
   883 			dcb.XonLim = (WORD)((iRxBufferSize / 2) -5);	//50%-5
       
   884 		else
       
   885 			dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3);	//75%
       
   886 
       
   887 		if (!SetCommStateP(iCommPort,&dcb))
       
   888 			return Emulator::LastError();
       
   889 
       
   890 		return KErrNone;
       
   891 		}
       
   892 	return Emulator::LastError();
       
   893 	}
       
   894 
       
   895 
       
   896 TInt DCommWins::RxBufferSize()
       
   897 	{
       
   898 	return iRxBufferSize;
       
   899 	}
       
   900 
       
   901 
       
   902 TBool DCommWins::IsATerminator(TText8 aChar)
       
   903 	{
       
   904 	TInt x;
       
   905 	for (x=0; x < iConfig->iTerminatorCount; x++)
       
   906 		if (aChar == iConfig->iTerminator[x])
       
   907 			return ETrue;
       
   908 	return EFalse;
       
   909 	}
       
   910 
       
   911 
       
   912 void DCommWins::ReSizeBuffer(TUint8*& aBuf, TInt& aBufLen, TPtr8& aDes, const TInt aNewLen)
       
   913 	{
       
   914 
       
   915 	if (aNewLen > KSerialBufferMaxSize)
       
   916 		Panic(ESerialBufferTooBig);
       
   917 
       
   918 	aBufLen = ((aNewLen + KSerialBufferIncrementSize-1) / KSerialBufferIncrementSize) * KSerialBufferIncrementSize;
       
   919 
       
   920 	if (aBufLen > KSerialBufferMaxSize)
       
   921 		aBufLen = KSerialBufferMaxSize;
       
   922 
       
   923 	if (!VirtualAlloc(aBuf, aBufLen, MEM_COMMIT,PAGE_READWRITE))
       
   924 		{
       
   925 		ReleaseBuffers();
       
   926 		Panic(ESerialBufferTooBig);
       
   927 		}
       
   928 	aDes.Set(aBuf, 0, aBufLen);
       
   929 	}
       
   930 
       
   931 
       
   932 void DCommWins::Write(DThread* aThread, TAny* aSrc, TInt aLength)
       
   933 
       
   934 	{
       
   935 	if (aLength==0)
       
   936 		{
       
   937 		RunCommThread(ETransmit0);
       
   938 		}
       
   939 	else
       
   940 		{
       
   941 		if (aLength > iOutBufLength)
       
   942 			ReSizeBuffer(iOutBufPtr, iOutBufLength, iOutDes, aLength);
       
   943 
       
   944 		//copy the data from the client
       
   945 		Kern::ThreadDesRead(aThread, aSrc, iOutDes, 0,0);
       
   946 		iOutDes.SetLength(aLength);
       
   947 		//tell the comms thread to write the data
       
   948 		RunCommThread(ETransmit);
       
   949 		}
       
   950 	}
       
   951 
       
   952 void DCommWins::NotifySignals(DThread* /*aThread*/, TInt aMask)
       
   953 	{
       
   954 	iSignalsWanted = aMask;
       
   955 	RunCommThread(ENotifySignals);
       
   956 	}
       
   957 
       
   958 
       
   959 void DCommWins::NotifyDataAvailable()
       
   960 	{
       
   961 	RunCommThread(ENotifyDataAvailable);
       
   962 	}
       
   963 
       
   964 
       
   965 void DCommWins::Read(DThread* /*aThread*/, TAny* /*aDest*/, TInt aLength)
       
   966 
       
   967 	{
       
   968 	TDriverCommand command;
       
   969 
       
   970 	if (aLength < 0)
       
   971 		{
       
   972 		iClientReadLength = Abs(aLength);
       
   973 		command = EReceiveOneOrMore;
       
   974 		}
       
   975 	else
       
   976 		{
       
   977 		iClientReadLength = aLength;
       
   978 		command = EReceive;
       
   979 		}
       
   980 
       
   981 	if (iClientReadLength > iInBufLength)
       
   982 		ReSizeBuffer(iInBufPtr, iInBufLength, iInDes, iClientReadLength);
       
   983 	
       
   984 	//tell the comms thread to read the data
       
   985 	RunCommThread(command);
       
   986 	}
       
   987 
       
   988 
       
   989 
       
   990 
       
   991 
       
   992 TUint DCommWins::Signals() const
       
   993 	{
       
   994 
       
   995 	ULONG signals=0;
       
   996 	GetCommModemStatusP(iCommPort,&signals);
       
   997 	TUint status=0;
       
   998 	if (signals&MS_CTS_ON)
       
   999 		status|=KSignalCTS;
       
  1000 	if (signals&MS_DSR_ON)
       
  1001 		status|=KSignalDSR;
       
  1002 	if (signals&MS_RING_ON)
       
  1003 		status|=KSignalRNG;
       
  1004 	if (signals&MS_RLSD_ON)
       
  1005 		status|=KSignalDCD;
       
  1006 	return(status|iSignals);
       
  1007 	}
       
  1008 
       
  1009 
       
  1010 void DCommWins::SetSignals(TUint aSetMask,TUint aClearMask)
       
  1011 	{
       
  1012 	if (aSetMask&KSignalRTS)
       
  1013 		{
       
  1014 		iSignals|=KSignalRTS;
       
  1015 		EscapeCommFunctionP(iCommPort,SETRTS);
       
  1016 		}
       
  1017 	if (aSetMask&KSignalDTR)
       
  1018 		{
       
  1019 		iSignals|=KSignalDTR;
       
  1020 		EscapeCommFunctionP(iCommPort,SETDTR);
       
  1021 		}
       
  1022 	if (aClearMask&KSignalRTS)
       
  1023 		{
       
  1024 		iSignals&=(~KSignalRTS);
       
  1025 		EscapeCommFunctionP(iCommPort,CLRRTS);
       
  1026 		}
       
  1027 	if (aClearMask&KSignalDTR)
       
  1028 		{
       
  1029 		iSignals&=(~KSignalDTR);
       
  1030 		EscapeCommFunctionP(iCommPort,CLRDTR);
       
  1031 		}
       
  1032 	}
       
  1033 
       
  1034 
       
  1035 
       
  1036 void DCommWins::CheckConfig(TCommConfigV01& /*aConfig*/)
       
  1037 	{
       
  1038 	// Do nothing
       
  1039 	}
       
  1040 
       
  1041 
       
  1042 
       
  1043 void DCommWins::Configure(TCommConfigV01 &aConfig)
       
  1044 //
       
  1045 // Ask comm thread to set up the serial port
       
  1046 //
       
  1047 	{
       
  1048 
       
  1049 	iConfig=&aConfig;
       
  1050 	if (iRunning)
       
  1051 		{
       
  1052 		RunCommThread(EConfigure);
       
  1053 		}
       
  1054 	else
       
  1055 		{
       
  1056 //		iCommand=EConfigure;
       
  1057 		DoConfigure();
       
  1058 		}
       
  1059 	}
       
  1060 
       
  1061 void DCommWins::DoConfigure()
       
  1062 //
       
  1063 // Set up the serial port
       
  1064 //
       
  1065 	{
       
  1066 
       
  1067 	DCB dcb = {0};
       
  1068 	//set the dcb size
       
  1069 	dcb.DCBlength = sizeof(dcb);
       
  1070 	if (!GetCommStateP(iCommPort,&dcb))
       
  1071 		return;
       
  1072 
       
  1073 			
       
  1074 	//stop if an error happens
       
  1075 	dcb.fAbortOnError = TRUE;
       
  1076 	
       
  1077 	//baud rate
       
  1078 	switch (iConfig->iRate)
       
  1079 		{
       
  1080 	case EBps75:
       
  1081 		dcb.BaudRate=75;
       
  1082 		break;
       
  1083 	case EBps110:
       
  1084 		dcb.BaudRate=110;
       
  1085 		break;
       
  1086 	case EBps134:
       
  1087 		dcb.BaudRate=134;
       
  1088 		break;
       
  1089 	case EBps150:
       
  1090 		dcb.BaudRate=150;
       
  1091 		break;
       
  1092 	case EBps300:
       
  1093 		dcb.BaudRate=300;
       
  1094 		break;
       
  1095 	case EBps600:
       
  1096 		dcb.BaudRate=600;
       
  1097 		break;
       
  1098 	case EBps1200:
       
  1099 		dcb.BaudRate=1200;
       
  1100 		break;
       
  1101 	case EBps1800:
       
  1102 		dcb.BaudRate=1800;
       
  1103 		break;
       
  1104 	case EBps2400:
       
  1105 		dcb.BaudRate=2400;
       
  1106 		break;
       
  1107 	case EBps4800:
       
  1108 		dcb.BaudRate=4800;
       
  1109 		break;
       
  1110 	case EBps7200:
       
  1111 		dcb.BaudRate=7200;
       
  1112 		break;
       
  1113 	case EBps9600:
       
  1114 		dcb.BaudRate=9600;
       
  1115 		break;
       
  1116 	case EBps19200:
       
  1117 		dcb.BaudRate=19200;
       
  1118 		break;
       
  1119 	case EBps38400:
       
  1120 		dcb.BaudRate=38400;
       
  1121 		break;
       
  1122 	case EBps57600:
       
  1123 		dcb.BaudRate=57600;
       
  1124 		break;
       
  1125 	case EBps115200:
       
  1126 		dcb.BaudRate=115200;
       
  1127 		break;
       
  1128 		}
       
  1129    
       
  1130 	switch (iConfig->iParity)
       
  1131 		{
       
  1132 	case EParityNone:
       
  1133 		dcb.Parity=NOPARITY;
       
  1134 		dcb.fParity = FALSE;
       
  1135 		break;
       
  1136 	case EParityEven:
       
  1137 		dcb.Parity=EVENPARITY;
       
  1138 		dcb.fParity = TRUE;
       
  1139 		break;
       
  1140 	case EParityOdd:
       
  1141 		dcb.Parity=ODDPARITY;
       
  1142 		dcb.fParity = TRUE;
       
  1143 		break;
       
  1144 	case EParityMark:
       
  1145 		dcb.Parity = MARKPARITY;
       
  1146 		dcb.fParity = TRUE;
       
  1147 		break;
       
  1148 	case EParitySpace:
       
  1149 		dcb.Parity = SPACEPARITY;
       
  1150 		dcb.fParity = TRUE;
       
  1151 		break;
       
  1152 		}
       
  1153 
       
  1154 	switch (iConfig->iParityError)
       
  1155 		{
       
  1156 	case KConfigParityErrorFail:
       
  1157 		dcb.fErrorChar = FALSE;
       
  1158 		break;
       
  1159 
       
  1160 	case KConfigParityErrorIgnore:
       
  1161 		dcb.fErrorChar = FALSE;
       
  1162 		dcb.fAbortOnError = FALSE;
       
  1163 		break;
       
  1164 
       
  1165 	case KConfigParityErrorReplaceChar:
       
  1166 		dcb.fErrorChar = TRUE;
       
  1167 		dcb.ErrorChar = iConfig->iParityErrorChar;
       
  1168 		break;
       
  1169 		}
       
  1170 
       
  1171 
       
  1172 	TUint& hs = iConfig->iHandshake;
       
  1173 
       
  1174 
       
  1175 	//SOFTWARE FLOW CONTROL
       
  1176 	dcb.fInX  = (hs & KConfigObeyXoff) ? TRUE : FALSE;
       
  1177 	dcb.fOutX = (hs & KConfigSendXoff) ? TRUE : FALSE;
       
  1178 
       
  1179 	dcb.XonChar = iConfig->iXonChar;
       
  1180 	dcb.XoffChar = iConfig->iXoffChar;
       
  1181 	dcb.ErrorChar = iConfig->iParityErrorChar;
       
  1182 
       
  1183 	//use rx buffer size to configure xon/xoff limits
       
  1184 	dcb.XoffLim = (WORD)(iRxBufferSize / 4);		//25%
       
  1185 	if (iConfig->iParityError & KConfigXonXoffDebug)
       
  1186 		dcb.XonLim = (WORD)((iRxBufferSize / 2) -5);	//50%-5
       
  1187 	else
       
  1188 		dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3);	//75%
       
  1189 
       
  1190 
       
  1191 
       
  1192 	//OUTPUT HARDWARE FLOW CONTROL
       
  1193 	//set out DSR control to be off
       
  1194 	dcb.fOutxDsrFlow = FALSE;
       
  1195 	dcb.fOutxCtsFlow = (hs & KConfigObeyCTS) ? TRUE : FALSE;
       
  1196 	dcb.fDsrSensitivity =  (hs & KConfigObeyDSR) ? TRUE : FALSE;
       
  1197 
       
  1198 
       
  1199 	if (hs & KConfigObeyDCD)
       
  1200 		{
       
  1201 		}
       
  1202 
       
  1203 	
       
  1204 	//INPUT HARDWARE FLOW CONTROL
       
  1205 	dcb.fRtsControl = (hs & KConfigFreeRTS) ? RTS_CONTROL_DISABLE : RTS_CONTROL_HANDSHAKE;
       
  1206 	dcb.fDtrControl = (hs & KConfigFreeDTR) ? DTR_CONTROL_DISABLE : DTR_CONTROL_ENABLE;
       
  1207 
       
  1208 
       
  1209 	//complete with KErrCommsLineFail if these are set and the line goes low
       
  1210 	iFailSignals = 0;
       
  1211 	if (hs & KConfigFailDSR)
       
  1212 		iFailSignals |= KSignalDSR;
       
  1213 	
       
  1214 	if (hs & KConfigFailCTS)
       
  1215 		iFailSignals |= KSignalCTS;
       
  1216 
       
  1217 	if (hs & KConfigFailDCD)
       
  1218 		iFailSignals |= KSignalDCD;
       
  1219 	
       
  1220 	
       
  1221 	iTerminatedRead = iConfig->iTerminatorCount > 0;
       
  1222 
       
  1223    	switch(iConfig->iDataBits)
       
  1224 		{
       
  1225 	case EData5:
       
  1226 		dcb.ByteSize=5;	
       
  1227 		break;
       
  1228 	case EData6:
       
  1229 		dcb.ByteSize=6;
       
  1230 		break;
       
  1231 	case EData7:
       
  1232 		dcb.ByteSize=7;
       
  1233 		break;
       
  1234 	case EData8:
       
  1235 		dcb.ByteSize=8;
       
  1236 		break;
       
  1237 		}
       
  1238 
       
  1239 	switch(iConfig->iStopBits)
       
  1240 		{
       
  1241 	case EStop1:
       
  1242 		dcb.StopBits=ONESTOPBIT;
       
  1243 		break;
       
  1244 	case EStop2:
       
  1245 		dcb.StopBits=TWOSTOPBITS;
       
  1246 		break;
       
  1247 		}
       
  1248 
       
  1249 
       
  1250 
       
  1251 	TInt error_r=KErrNone;
       
  1252 	if(!SetCommStateP(iCommPort,&dcb))
       
  1253 		error_r=GetLastError();
       
  1254 
       
  1255 // Clear any error we may have caused
       
  1256 //
       
  1257 	DWORD err,res;
       
  1258 	COMSTAT s;
       
  1259 	if (ClearCommError(iCommPort,&err,&s)==FALSE)
       
  1260 		res=GetLastError();
       
  1261 
       
  1262 	}
       
  1263 
       
  1264 void DCommWins::Caps(TDes8 &aCaps) const
       
  1265 //
       
  1266 // Return the current capabilities
       
  1267 //
       
  1268 	{
       
  1269 
       
  1270 	GetWinsCommsCaps(aCaps);
       
  1271 	}
       
  1272 
       
  1273 
       
  1274 void DCommWins::WaitForEvent()
       
  1275 	{
       
  1276 
       
  1277 	HANDLE objects[4];
       
  1278 
       
  1279 
       
  1280 	iReadOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL); 
       
  1281 	iWriteOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
       
  1282 	iSignalOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
       
  1283 	objects[0]=iSignalOverLapped.hEvent; // iCommPort;
       
  1284 	objects[1]=iCommThreadSem;
       
  1285 	objects[2]=iWriteOverLapped.hEvent;
       
  1286 	objects[3]=iReadOverLapped.hEvent;
       
  1287 
       
  1288 	FOREVER
       
  1289 		{
       
  1290 		DWORD ret=WaitForMultipleObjectsEx(4,objects,FALSE,INFINITE,TRUE);
       
  1291 		switch (ret)
       
  1292 			{
       
  1293 		case WAIT_OBJECT_0:
       
  1294 			{
       
  1295 			//			EnterCritical();
       
  1296 
       
  1297 			if (iDataAvailableNotification)
       
  1298 				{
       
  1299 				DataAvailableCompletion(this);
       
  1300 				iDataAvailableNotification = EFalse;	//stop us repeatedly reporting it
       
  1301 				}
       
  1302 
       
  1303 			// Detect breaks
       
  1304 			if (iSignalStatus & EV_BREAK)
       
  1305 				{
       
  1306 				iBreakDetected=ETrue; // the read will complete with an error
       
  1307 				}
       
  1308 				
       
  1309 			TUint currentSignals = Signals();
       
  1310 
       
  1311 			//mask out all the signals but the ones we are interested in
       
  1312 			iLineFail = (iFailSignals & currentSignals) != iFailSignals;
       
  1313 			if (iLineFail)
       
  1314 				{
       
  1315 				//if we have the handshake options of
       
  1316 				//KConfigFailDSR, KConfigFailDCD KFailConfigCTS set
       
  1317 				//we need to do something if any of them are low so
       
  1318 				//complete any outstanding ops with failure
       
  1319 				if (iReadPending)
       
  1320 					{
       
  1321 					//we have a read to complete
       
  1322 					iRXLineFail = ETrue;
       
  1323 					PurgeComm(iCommPort, PURGE_RXABORT);
       
  1324 					}
       
  1325 
       
  1326 				if (iWritePending)
       
  1327 					{
       
  1328 					//we have a write to complete
       
  1329 					iTXLineFail = ETrue;
       
  1330 					PurgeComm(iCommPort, PURGE_TXABORT);
       
  1331 					}
       
  1332 				}
       
  1333 
       
  1334 
       
  1335 			//iSignalsRequested will only have bits set if outstanding request
       
  1336 			TUint changed = (currentSignals ^ iSavedSignals) & iSignalsRequested;
       
  1337 			if (changed) 
       
  1338 				{
       
  1339 				SignalCompletion(this, KErrNone, changed, currentSignals);
       
  1340 				iSavedSignals = currentSignals;
       
  1341 				iSignalsRequested = 0;				//stop us repeatedly reporting it.
       
  1342 												//iSignalsRequested is setup in the call to notify
       
  1343 				}
       
  1344 			
       
  1345 			if (iWritePending == ETransmit0 && (currentSignals & KSignalCTS) != 0)
       
  1346 				WriteCompletion(this, KErrNone, 0);
       
  1347 
       
  1348 			//request another notification event.  All events are requested.
       
  1349 			iSignalStatus=0;
       
  1350 			DWORD commErrors;
       
  1351 			BOOL res;
       
  1352 			DWORD lastError = 0;
       
  1353 			COMSTAT cstat;
       
  1354 
       
  1355 			do
       
  1356 				{
       
  1357 				ClearCommError(iCommPort,&commErrors,&cstat);
       
  1358 				res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
       
  1359 				if (!res)
       
  1360 					lastError = GetLastError();
       
  1361 				}
       
  1362 			while((!res) && (lastError != ERROR_IO_PENDING));
       
  1363 
       
  1364 			break;
       
  1365 			}
       
  1366 
       
  1367 		case WAIT_OBJECT_0+1:
       
  1368 //
       
  1369 // iCommThreadSemaphore has been signalled
       
  1370 //
       
  1371 			DriverCommand(iCommand);
       
  1372 			break;
       
  1373 		case WAIT_OBJECT_0+2:
       
  1374 			//
       
  1375 			//	Write completion
       
  1376 			//
       
  1377 			{
       
  1378 
       
  1379 			DWORD len = 0;
       
  1380 			TInt error = KErrNone;
       
  1381 			if (!GetOverlappedResult(iCommPort, &iWriteOverLapped, &len, FALSE))
       
  1382 				error = Emulator::LastError();
       
  1383 			
       
  1384 			COMSTAT s;
       
  1385 			DWORD err = 0;
       
  1386 			ClearCommError(iCommPort,&err,&s);
       
  1387 
       
  1388 			//if we are failing if one or more of CTS, DSR, DCD go low
       
  1389 			if (iTXLineFail)
       
  1390 				{
       
  1391 				error = KErrCommsLineFail;
       
  1392 				iTXLineFail = EFalse;
       
  1393 				}
       
  1394 			else if (err)
       
  1395 				{
       
  1396 				if (err & CE_FRAME)
       
  1397 					error = KErrCommsFrame;
       
  1398 				else if (err & CE_OVERRUN)
       
  1399 					error = KErrCommsOverrun;
       
  1400 				else if (err & CE_RXPARITY)
       
  1401 					error = KErrCommsParity;
       
  1402 				}
       
  1403 
       
  1404 			WriteCompletion(this, error, len);
       
  1405 			break;
       
  1406 			}
       
  1407 
       
  1408 		case WAIT_OBJECT_0+3:
       
  1409 			//
       
  1410 			//	Read completion
       
  1411 			//
       
  1412 			{
       
  1413 			DWORD len = 0;
       
  1414 			TInt error = KErrNone;
       
  1415 			if (!GetOverlappedResult(iCommPort, &iReadOverLapped, &len, FALSE))
       
  1416 				{
       
  1417 				// May have a break already detected to report
       
  1418 				if (iBreakDetected)
       
  1419 					{
       
  1420 					error=KErrCommsBreak;
       
  1421 					iBreakDetected=EFalse;
       
  1422 					}
       
  1423 				else
       
  1424 					error = Emulator::LastError();
       
  1425 				}
       
  1426 			else
       
  1427 				iBreakDetected=EFalse; // No error, so any breaks have finished
       
  1428 			
       
  1429 			COMSTAT s;
       
  1430 			DWORD err = 0;
       
  1431 			ClearCommError(iCommPort,&err,&s);
       
  1432 
       
  1433 			//if we are failing if one or more of CTS, DSR, DCD go low
       
  1434 			if (iRXLineFail)
       
  1435 				{
       
  1436 				error = KErrCommsLineFail;
       
  1437 				iRXLineFail = EFalse;
       
  1438 				}
       
  1439 			else if (err)
       
  1440 				{
       
  1441 				if (err & CE_FRAME)
       
  1442 					error = KErrCommsFrame;
       
  1443 				else if (err & CE_OVERRUN)
       
  1444 					error = KErrCommsOverrun;
       
  1445 				else if (err & CE_RXPARITY)
       
  1446 					error = KErrCommsParity;
       
  1447 				}
       
  1448 
       
  1449 			ReadCompletion(this, error, len);
       
  1450 			break;
       
  1451 			}
       
  1452 
       
  1453 		case WAIT_IO_COMPLETION:
       
  1454 			break;
       
  1455 
       
  1456 		default:
       
  1457 			Emulator::LastError();
       
  1458 			FAULT();
       
  1459 			}
       
  1460 		}
       
  1461 	}
       
  1462 
       
  1463 void DCommWins::DriverCommand(TDriverCommand aCommand)
       
  1464 //
       
  1465 // Do a driver command - executed when the semaphore has been signalled in the comm port thread
       
  1466 //
       
  1467 	{
       
  1468 	switch (aCommand)
       
  1469 		{
       
  1470 	case ESetBreak:
       
  1471 		FlushFileBuffers(iCommPort);
       
  1472 		SetCommBreak(iCommPort);
       
  1473 		break;
       
  1474 
       
  1475 	case EClearBreak:
       
  1476 		ClearCommBreak(iCommPort);
       
  1477 		break;
       
  1478 
       
  1479 	case ETransmit0:
       
  1480 		
       
  1481 		if (!iWritePending)
       
  1482 			{
       
  1483 			if ((iConfig->iHandshake & KConfigObeyCTS) != 0 && (Signals() & KSignalCTS) == 0)
       
  1484 				iWritePending = ETransmit0;
       
  1485 			else
       
  1486 				DoWriteComplete(KErrNone);
       
  1487 			}
       
  1488 		break;
       
  1489 
       
  1490 	case ETransmit:
       
  1491 		
       
  1492 		if (!iWritePending)
       
  1493 			{
       
  1494 			COMMTIMEOUTS ct;
       
  1495 			int r = GetCommTimeouts(iCommPort, &ct);
       
  1496 			ct.WriteTotalTimeoutConstant = 0;
       
  1497 			ct.WriteTotalTimeoutMultiplier = 0;
       
  1498 			r = SetCommTimeouts(iCommPort, &ct);
       
  1499 
       
  1500 			WriteFileP(iCommPort,iOutDes.Ptr(), iOutDes.Length(), &dummyLen, &iWriteOverLapped);
       
  1501 			iWritePending = ETransmit;
       
  1502 			iTransmitting= ETrue;
       
  1503 			}
       
  1504 		break;
       
  1505 
       
  1506 	case EStart:
       
  1507 		{
       
  1508 		iSignalStatus=0;
       
  1509 		iSignalStatus=0;
       
  1510 		DWORD commErrors;
       
  1511 		BOOL res;
       
  1512 		DWORD lastError = 0;
       
  1513 		COMSTAT cstat;
       
  1514 
       
  1515 		do
       
  1516 			{
       
  1517 			ClearCommError(iCommPort,&commErrors,&cstat);
       
  1518 			res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
       
  1519 			if (!res)
       
  1520 				lastError = GetLastError();
       
  1521 			}
       
  1522 		while((!res) && (lastError != ERROR_IO_PENDING));
       
  1523 		}
       
  1524 		break;
       
  1525 	
       
  1526 	case EStop:
       
  1527         // Flush last write
       
  1528 		if(iWritePending == ETransmit)
       
  1529 			{
       
  1530 			WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
       
  1531 			FlushFileBuffers(iCommPort);
       
  1532 			}
       
  1533         iWritePending=0;
       
  1534         iTransmitting=EFalse;
       
  1535 		// Fall through
       
  1536 	case EStopNoDrain:
       
  1537 		// Cancel any pending writes
       
  1538         if(iWritePending == ETransmit)
       
  1539 		    {
       
  1540 			PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
       
  1541             WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
       
  1542 		    }   
       
  1543         iWritePending=0;
       
  1544 		iTransmitting=EFalse;
       
  1545 		iStopping=ETrue;
       
  1546         if(iRunning)
       
  1547             {
       
  1548             SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR);
       
  1549             WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
       
  1550             }
       
  1551 		break;
       
  1552 
       
  1553 	case EDie:	
       
  1554 		SignalDriverThread();
       
  1555 		ExitThread(1);
       
  1556 		break;
       
  1557 	
       
  1558 	case EConfigure:
       
  1559 		DoConfigure();
       
  1560 		break;
       
  1561 	
       
  1562 	case ETransmitCancel:
       
  1563 		if (iWritePending == ETransmit)
       
  1564 			PurgeComm(iCommPort, PURGE_TXABORT);
       
  1565 //		else if (iWritePending == ETransmit0)
       
  1566 //			{
       
  1567 			// careful - this runs in the context of the kernel thread, not the event thread
       
  1568 		iLdd->iTxError = KErrCancel;
       
  1569 		iLdd->iTxCompleteDfc.Enque();
       
  1570 //			}
       
  1571 		break;
       
  1572 
       
  1573 	case EReceive:
       
  1574 		if (!iReadPending)
       
  1575 			{
       
  1576 			COMMTIMEOUTS ct;
       
  1577 			int r = GetCommTimeouts(iCommPort, &ct);
       
  1578 			ct.ReadIntervalTimeout = 0;
       
  1579 			ct.ReadTotalTimeoutMultiplier = 0;
       
  1580 			ct.ReadTotalTimeoutConstant = 0;
       
  1581 			r = SetCommTimeouts(iCommPort, &ct);
       
  1582 
       
  1583 			//if we are doing a terminated read.... we need to do it a byte at a time!
       
  1584 			if (iTerminatedRead)
       
  1585 				{
       
  1586 				iReadSoFar = 0;
       
  1587 				ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped);
       
  1588 				}
       
  1589 			else
       
  1590 				{
       
  1591 				ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
       
  1592 				}
       
  1593 
       
  1594 			iReadPending = EReceive;
       
  1595 			}
       
  1596 		break;
       
  1597 
       
  1598 	case EReceiveOneOrMore:
       
  1599 		if (!iReadPending)
       
  1600 			{
       
  1601 			COMMTIMEOUTS ct;
       
  1602 			int r = GetCommTimeouts(iCommPort, &ct);
       
  1603 			ct.ReadIntervalTimeout = MAXDWORD;
       
  1604 			ct.ReadTotalTimeoutMultiplier = MAXDWORD;
       
  1605 			ct.ReadTotalTimeoutConstant = KReadOneOrMoreTimeout;
       
  1606 			r = SetCommTimeouts(iCommPort, &ct);
       
  1607 
       
  1608 			//if we are doing a terminated read....
       
  1609 			if (iTerminatedRead)
       
  1610 				{
       
  1611 				iReadSoFar = 0;
       
  1612 				ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped);
       
  1613 				}
       
  1614 			else
       
  1615 				{
       
  1616 				ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
       
  1617 				}
       
  1618 
       
  1619 			iReadPending = EReceiveOneOrMore;
       
  1620 			}
       
  1621 		break;
       
  1622 
       
  1623 	case EReceiveCancel:
       
  1624 		if (iReadPending)
       
  1625 			PurgeComm(iCommPort, PURGE_RXABORT);
       
  1626 		else if (iDataAvailableNotification)
       
  1627 			DataAvailableNotificationCancel();
       
  1628 		break;
       
  1629 
       
  1630 	case ENotifyDataAvailable:
       
  1631 		{
       
  1632 		iDataAvailableNotification = ETrue;
       
  1633 		//setup the comms notifications for data available
       
  1634 		break;
       
  1635 		}
       
  1636 
       
  1637 	case ENotifySignals:
       
  1638 		{
       
  1639 		TUint currentSignals = Signals();
       
  1640 		TUint changed = (currentSignals ^ iSavedSignals) & iSignalsWanted;
       
  1641 		if (changed) 
       
  1642 			{
       
  1643 			SignalCompletion(this, KErrNone, changed, currentSignals);
       
  1644 			iSavedSignals = currentSignals;
       
  1645 			iSignalsWanted = 0;				
       
  1646 			}
       
  1647 		else
       
  1648 			iSignalsRequested = iSignalsWanted;	//checked when signals change
       
  1649 		}
       
  1650 		break;
       
  1651 
       
  1652 
       
  1653 	default:
       
  1654 		// Panic(EUnknownCommand);
       
  1655 		break;
       
  1656 		}
       
  1657 	iCommand=EInvalidCommand;
       
  1658 	SignalDriverThread();
       
  1659 	}
       
  1660 
       
  1661 
       
  1662 TDfcQue* DCommWins::DfcQ(TInt /*aUnit*/)
       
  1663 	{
       
  1664 	return Kern::DfcQue0();
       
  1665 	}
       
  1666 
       
  1667 
       
  1668 TInt DCommWins::ValidateConfig(const TCommConfigV01 &aConfig) const
       
  1669 //
       
  1670 // Check a config structure.
       
  1671 //
       
  1672 	{
       
  1673 	if(aConfig.iRate & EBpsSpecial)
       
  1674 		return KErrNotSupported;
       
  1675 
       
  1676 	switch (aConfig.iParity)
       
  1677 		{
       
  1678 		case EParityNone:
       
  1679 		case EParityOdd:
       
  1680 		case EParityEven:
       
  1681 			break;
       
  1682 		default:
       
  1683 			return KErrNotSupported;
       
  1684 		}
       
  1685 	switch (aConfig.iRate)
       
  1686 		{
       
  1687 		case EBps50:
       
  1688 		case EBps75:
       
  1689 		case EBps134:
       
  1690 		case EBps1800:
       
  1691 		case EBps2000:
       
  1692 		case EBps3600:
       
  1693 		case EBps7200:
       
  1694 			return KErrNotSupported;
       
  1695 		default:
       
  1696 			break;
       
  1697 		};
       
  1698 	return KErrNone;
       
  1699 	}
       
  1700 
       
  1701 inline TBool DCommWins::LineFail()
       
  1702 	{
       
  1703 	return iLineFail;
       
  1704 	}
       
  1705 
       
  1706 
       
  1707 
       
  1708 DECLARE_STANDARD_PDD()
       
  1709 	{
       
  1710 	return new DDriverComm;
       
  1711 	}
       
  1712