1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/boardsupport/emulator/emulatorbsp/specific/serialpdd.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1712 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// wins/specific/serialpdd.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include "winscomm.h"
1.22 +#include "nk_priv.h"
1.23 +#include "nk_plat.h"
1.24 +#include <emulator.h>
1.25 +
1.26 +#define WIN32_LEAN_AND_MEAN
1.27 +#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
1.28 +#include <windows.h>
1.29 +#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
1.30 +
1.31 +#ifdef FAULT
1.32 +#undef FAULT
1.33 +#endif
1.34 +#define FAULT() Kern::Fault(__FILE__,__LINE__)
1.35 +
1.36 +_LIT(KComName, "\\\\.\\com");
1.37 +
1.38 +// needs ldd version..
1.39 +const TInt KMinimumLddMajorVersion=1;
1.40 +const TInt KMinimumLddMinorVersion=1;
1.41 +const TInt KMinimumLddBuild=1;
1.42 +
1.43 +//used for the read and write buffers in the driver.
1.44 +//large buffer reserved so any transfer to/from the client can fit into a driver buffer
1.45 +const TInt KSerialBufferMaxSize = 0x800000;
1.46 +const TInt KSerialBufferInitialSize = 0x10000;
1.47 +const TInt KSerialBufferIncrementSize = 0x1000; //granularity. must be power of 2
1.48 +
1.49 +
1.50 +const DWORD KReadOneOrMoreTimeout = MAXDWORD-1; //milliseconds
1.51 +
1.52 +
1.53 +//buffer sizes passed to NT for setting its own driver buffer sizes
1.54 +const TInt KDefaultWinNTReadBufSize = 1024;
1.55 +const TInt KDefaultWinNTWriteBufSize = 1024;
1.56 +
1.57 +static DWORD dummyLen=0;
1.58 +
1.59 +enum TDCommWinsFault
1.60 + {
1.61 + EWindowsUnexpectedError,
1.62 + EUnknownCommand,
1.63 + EBadIOLen,
1.64 + EEofOnSerial,
1.65 + EWriteEarlyCompletion,
1.66 + ELineErrorNotReported,
1.67 + ESerialBufferTooBig,
1.68 + EReadLength,
1.69 + };
1.70 +
1.71 +
1.72 +class DDriverComm : public DPhysicalDevice
1.73 + {
1.74 +public:
1.75 + DDriverComm();
1.76 + virtual TInt Install();
1.77 + virtual TInt Remove();
1.78 + virtual void GetCaps(TDes8 &aDes) const;
1.79 + virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
1.80 + virtual TInt Validate(TInt aUnit, const TDesC8* aInfo, const TVersion &aVer);
1.81 + };
1.82 +
1.83 +
1.84 +class DCommWins : public DComm
1.85 + {
1.86 +public:
1.87 + enum TDriverCommand {ESetBreak=1,EClearBreak,ETransmit,ETransmit0,
1.88 + EGetSignals,ESetSignals,EConfigure,
1.89 + EStop,EStopNoDrain,EStart,EDie, ETransmitCancel,
1.90 + EReceive, EReceiveOneOrMore, EReceiveCancel,ENotifyDataAvailable,
1.91 + ENotifySignals, EInvalidCommand};
1.92 +public:
1.93 + DCommWins();
1.94 + ~DCommWins();
1.95 + virtual TInt Start();
1.96 + virtual void Stop(TStopMode aMode);
1.97 + virtual void Break(TBool aState);
1.98 + virtual void Write(DThread* aThread, TAny *aTxDes, TInt aLength);
1.99 + virtual void Read(DThread* aThread, TAny *aTxDes, TInt aLength);
1.100 + virtual void NotifySignals(DThread* aThread, TInt aMask);
1.101 + virtual void NotifyDataAvailable();
1.102 + virtual TUint Signals() const;
1.103 + virtual void SetSignals(TUint aSetMask,TUint aClearMask);
1.104 + virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const;
1.105 + virtual void Configure(TCommConfigV01 &aConfig);
1.106 + virtual void Caps(TDes8 &aCaps) const;
1.107 + virtual void CheckConfig(TCommConfigV01& aConfig);
1.108 + virtual TDfcQue* DfcQ(TInt aUnit);
1.109 +
1.110 + inline void CheckTxBuffer();
1.111 + inline TBool Transmitting();
1.112 + virtual TInt RxCount();
1.113 + virtual void ResetBuffers(TBool);
1.114 + virtual TInt SetRxBufferSize(TInt aSize);
1.115 + virtual TInt RxBufferSize();
1.116 + virtual TDes8* RxBuffer();
1.117 + virtual void DoConfigure();
1.118 + virtual TBool AreAnyPending();
1.119 + virtual void ReadCancel();
1.120 + virtual void WriteCancel();
1.121 + virtual void SignalChangeCancel();
1.122 + TInt DoCreate(TInt aUnit,const TDesC8 *aInfo);
1.123 + void WaitForEvent();
1.124 + void DriverCommand(TDriverCommand aCommand);
1.125 + void DoWriteComplete(TInt aErr);
1.126 + void DoReadComplete(TInt aErr, TInt aBytes);
1.127 + void DoSignalCompletion(TInt aError, TUint changed, TUint aValues);
1.128 + void DoDataAvailableCompletion();
1.129 + void RunCommThread(TDriverCommand aCommand);
1.130 + inline void SignalDriverThread();
1.131 + inline TBool LineFail();
1.132 +
1.133 +private:
1.134 + void ReleaseBuffers();
1.135 + void ReSizeBuffer(TUint8*& aBuf, TInt& iBufLen, TPtr8& aDes, const TInt aNewLen);
1.136 + TBool IsATerminator(TText8 aChar);
1.137 + void CompleteRead(TInt aLength);
1.138 + void DataAvailableNotificationCancel();
1.139 +
1.140 +
1.141 +private:
1.142 + TInt iWritePending;
1.143 + TInt iReadPending;
1.144 + TBool iStopping;
1.145 + TBool iRunning;
1.146 + TDriverCommand iCommand;
1.147 + TCommConfigV01 *iConfig;
1.148 + TUint iSignals;
1.149 + TUint iFailSignals;
1.150 + TUint iSavedSignals;
1.151 + TBool iLineFail;
1.152 + TBool iRXLineFail;
1.153 + TBool iTXLineFail;
1.154 +
1.155 + TUint8 * iInBufPtr; //input buffer used by driver.
1.156 + TInt iInBufLength;
1.157 + TPtr8 iInDes;
1.158 +
1.159 + TInt iReadSoFar;
1.160 + TBool iTerminatedRead; //true if we are reading with 1 or more terminating characters
1.161 +
1.162 + TUint8 * iOutBufPtr;
1.163 + TInt iOutBufLength;
1.164 + TPtr8 iOutDes;
1.165 +
1.166 + TInt iRxBufferSize; //size of receivebuffer passed to windows & set by calls to SetReceiveBufferSize
1.167 + //used to determine xon and xoff levels
1.168 + TUint iSignalsRequested; //mask of signals we are waiting for
1.169 + TUint iSignalsWanted; //mask we are asked to check
1.170 + TBool iDataAvailableNotification;
1.171 + HANDLE iThread;
1.172 + HANDLE iCommThreadSem;
1.173 + HANDLE iDriverThreadSem;
1.174 + HANDLE iCommPort;
1.175 + DWORD iThreadID;
1.176 + DWORD iSignalStatus;
1.177 + OVERLAPPED iReadOverLapped;
1.178 + OVERLAPPED iWriteOverLapped;
1.179 + OVERLAPPED iSignalOverLapped;
1.180 +
1.181 + TInt iClientReadLength; //how much data the client has requested in a read
1.182 + TBool iBreakDetected;
1.183 + };
1.184 +
1.185 +void Panic(TDCommWinsFault aFault)
1.186 +//
1.187 +// Panic the driver
1.188 +//
1.189 + {
1.190 + Kern::PanicCurrentThread(_L("DCommWins"), aFault);
1.191 + }
1.192 +
1.193 +
1.194 +TUint commThread(DCommWins *comm)
1.195 +//
1.196 +// Comm thread entry point
1.197 +//
1.198 + {
1.199 +
1.200 + comm->WaitForEvent();
1.201 + return 0;
1.202 + }
1.203 +
1.204 +VOID WINAPI WriteCompletion(DCommWins *aDrv, DWORD aErr,DWORD /*numBytes*/)
1.205 + {
1.206 +
1.207 + aDrv->DoWriteComplete(aErr);
1.208 + }
1.209 +
1.210 +
1.211 +VOID WINAPI ReadCompletion(DCommWins *aDrv, DWORD aErr,DWORD numBytes)
1.212 + {
1.213 +
1.214 + aDrv->DoReadComplete(aErr, numBytes);
1.215 + }
1.216 +
1.217 +VOID WINAPI SignalCompletion(DCommWins *aDrv, TInt aError, TUint aChanged, TUint aValues)
1.218 + {
1.219 + aDrv->DoSignalCompletion(aError, aChanged, aValues);
1.220 + }
1.221 +
1.222 +VOID WINAPI DataAvailableCompletion(DCommWins *aDrv)
1.223 + {
1.224 + aDrv->DoDataAvailableCompletion();
1.225 + }
1.226 +
1.227 +
1.228 +
1.229 +BOOL WINAPI EscapeCommFunctionP(HANDLE hFile,DWORD dwFunc)
1.230 + {
1.231 + DWORD err;
1.232 + DWORD lastError = 0;
1.233 + BOOL res;
1.234 + COMSTAT s;
1.235 +
1.236 + do
1.237 + {
1.238 + ClearCommError(hFile, &err, &s);
1.239 + res = EscapeCommFunction(hFile,dwFunc);
1.240 + if(!res)
1.241 + lastError = GetLastError();
1.242 + }
1.243 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.244 +
1.245 + return(res);
1.246 + }
1.247 +
1.248 +
1.249 +BOOL WINAPI GetCommModemStatusP(HANDLE hFile,LPDWORD lpModemStat)
1.250 + {
1.251 + DWORD err;
1.252 + DWORD lastError = 0;
1.253 + BOOL res;
1.254 + COMSTAT s;
1.255 +
1.256 + do
1.257 + {
1.258 + ClearCommError(hFile, &err, &s);
1.259 + res = GetCommModemStatus(hFile,lpModemStat);
1.260 + if(!res)
1.261 + lastError = GetLastError();
1.262 + }
1.263 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.264 +
1.265 + return(res);
1.266 + }
1.267 +
1.268 +
1.269 +BOOL WINAPI GetCommStateP(HANDLE hFile,LPDCB lpDCB)
1.270 + {
1.271 + DWORD err;
1.272 + DWORD lastError = 0;
1.273 + BOOL res;
1.274 + COMSTAT s;
1.275 +
1.276 + do
1.277 + {
1.278 + ClearCommError(hFile,&err,&s);
1.279 + res = GetCommState(hFile,lpDCB);
1.280 + if (!res)
1.281 + lastError = GetLastError();
1.282 + }
1.283 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.284 +
1.285 + return(res);
1.286 + }
1.287 +
1.288 +BOOL WINAPI SetCommStateP(HANDLE hFile,LPDCB lpDCB)
1.289 + {
1.290 + DWORD err;
1.291 + DWORD lastError = 0;
1.292 + BOOL res;
1.293 + COMSTAT s;
1.294 +
1.295 + do
1.296 + {
1.297 + ClearCommError(hFile, &err, &s);
1.298 + res = SetCommState(hFile, lpDCB);
1.299 + if (!res)
1.300 + lastError = GetLastError();
1.301 + }
1.302 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.303 +
1.304 + return(res);
1.305 + }
1.306 +
1.307 +BOOL WINAPI SetCommMaskP(HANDLE hFile,DWORD dwEvtMask)
1.308 + {
1.309 + DWORD err;
1.310 + DWORD lastError = 0;
1.311 + BOOL res;
1.312 + COMSTAT s;
1.313 +
1.314 + do
1.315 + {
1.316 + ClearCommError(hFile, &err, &s);
1.317 + res = SetCommMask(hFile, dwEvtMask);
1.318 + if (!res)
1.319 + lastError = GetLastError();
1.320 + }
1.321 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.322 +
1.323 + return(res);
1.324 + }
1.325 +
1.326 +BOOL WINAPI WriteFileP(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)
1.327 + {
1.328 + DWORD err;
1.329 + DWORD lastError = 0;
1.330 + BOOL res;
1.331 + COMSTAT s;
1.332 +
1.333 + do
1.334 + {
1.335 + ClearCommError(hFile, &err, &s);
1.336 + res = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
1.337 + if (!res)
1.338 + lastError = GetLastError();
1.339 + }
1.340 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.341 +
1.342 + return(res);
1.343 + }
1.344 +
1.345 +BOOL WINAPI ReadFileP(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
1.346 + {
1.347 + DWORD err;
1.348 + DWORD lastError = 0;
1.349 + BOOL res;
1.350 + COMSTAT s;
1.351 +
1.352 + do
1.353 + {
1.354 + ClearCommError(hFile, &err, &s);
1.355 + res = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
1.356 + if (!res)
1.357 + lastError = GetLastError();
1.358 + }
1.359 + while((!res) && (lastError == ERROR_OPERATION_ABORTED));
1.360 +
1.361 + return(res);
1.362 + }
1.363 +
1.364 +
1.365 +
1.366 +
1.367 +DDriverComm::DDriverComm()
1.368 + {
1.369 +#if defined (__COM_ONE_ONLY__)
1.370 + iUnitsMask=0x1; // Support units 0
1.371 +#elif defined (__COM_TWO_ONLY__)
1.372 + iUnitsMask=0x2; // Support units 1
1.373 +#else
1.374 + iUnitsMask=0x3ff; // Support units 0 to 9
1.375 +#endif
1.376 +
1.377 + iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
1.378 + }
1.379 +
1.380 +TInt DDriverComm::Install()
1.381 + {
1.382 +#if defined (__COM_ONE_ONLY__)
1.383 + TPtrC buf=_L("Comm.Wins1");
1.384 + return(SetName(&buf));
1.385 +#elif defined (__COM_TWO_ONLY__)
1.386 + TPtrC buf=_L("Comm.Wins2");
1.387 + return(SetName(&buf));
1.388 +#else
1.389 + TPtrC buf=_L("Comm.Wins");
1.390 + return(SetName(&buf));
1.391 +#endif
1.392 + }
1.393 +
1.394 +TInt DDriverComm::Remove()
1.395 + {
1.396 + return(KErrNone);
1.397 + }
1.398 +
1.399 +
1.400 +TInt DDriverComm::Validate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
1.401 +//
1.402 +// Validate the requested configuration
1.403 +//
1.404 + {
1.405 + if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
1.406 + return KErrNotSupported;
1.407 +#if defined (__COM_ONE_ONLY__)
1.408 + if (aUnit!=0)
1.409 + return KErrNotSupported;
1.410 +#elif defined (__COM_TWO_ONLY__)
1.411 + if (aUnit!=1)
1.412 + return KErrNotSupported;
1.413 +#endif
1.414 + // leave Unit check to CreateFile
1.415 + return KErrNone;
1.416 + }
1.417 +
1.418 +
1.419 +void GetWinsCommsCaps(TDes8 &aCaps)
1.420 + {
1.421 + TCommCaps3 capsBuf;
1.422 + TCommCapsV03 &c=capsBuf();
1.423 +//
1.424 +// All rates except 50,2000, 3600 and special
1.425 +//
1.426 + c.iRate=KCapsBps75|KCapsBps110|KCapsBps134|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps1800|KCapsBps2400|KCapsBps4800|KCapsBps7200|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200;
1.427 +
1.428 + c.iDataBits=0xf; // All data sizes
1.429 + c.iStopBits=0x3; // 1 and 2 stop bits
1.430 + c.iParity=0x7; // None, Even and Odd
1.431 + c.iHandshake = 0x3BF; //all except KConfigObeyDCD
1.432 + c.iSignals=0x3f; // All signals
1.433 + c.iSIR=0;//No Ir
1.434 + c.iNotificationCaps=KNotifySignalsChangeSupported|KNotifyDataAvailableSupported;
1.435 + c.iRoleCaps=0;
1.436 + c.iFlowControlCaps=0;
1.437 + c.iBreakSupported=ETrue;
1.438 + aCaps.FillZ(aCaps.MaxLength());
1.439 + aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
1.440 + }
1.441 +
1.442 +void DDriverComm::GetCaps(TDes8 &aDes) const
1.443 + {
1.444 + GetWinsCommsCaps(aDes);
1.445 + }
1.446 +
1.447 +TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit,const TDesC8* aInfo,const TVersion& aVer)
1.448 + {
1.449 +
1.450 + if (!Kern::QueryVersionSupported(iVersion,aVer))
1.451 + return KErrNotSupported;
1.452 +
1.453 + DCommWins *pD= new DCommWins;
1.454 + if (!pD) return KErrNoMemory;
1.455 +
1.456 + TInt ret=pD->DoCreate(aUnit,aInfo);
1.457 +
1.458 + if (ret!=KErrNone)
1.459 + {
1.460 + delete pD;
1.461 + return ret;
1.462 + }
1.463 +
1.464 + aChannel = pD;
1.465 +
1.466 + return KErrNone;
1.467 + }
1.468 +
1.469 +void DCommWins::DoWriteComplete(TInt aErr)
1.470 + {
1.471 + iWritePending = 0;
1.472 + iTransmitting = EFalse;
1.473 + StartOfInterrupt();
1.474 + iLdd->iTxError = aErr;
1.475 + iLdd->iTxCompleteDfc.Add();
1.476 + EndOfInterrupt();
1.477 + }
1.478 +
1.479 +
1.480 +
1.481 +void DCommWins::DoSignalCompletion(TInt aError, TUint aChanged, TUint aValues)
1.482 + {
1.483 + //aValues contains the signal values. EPOC constants
1.484 + //aChanged contains the signals which have changed
1.485 + //we return the signal values
1.486 + TUint res = aValues & iSignalsWanted;
1.487 + res |= (aChanged << 12);
1.488 +
1.489 + iLdd->iSignalResult = res;
1.490 + iLdd->iSignalError = aError;
1.491 + StartOfInterrupt();
1.492 + iLdd->iSigNotifyDfc.Add();
1.493 + EndOfInterrupt();
1.494 + }
1.495 +
1.496 +void DCommWins::DoDataAvailableCompletion()
1.497 + {
1.498 + StartOfInterrupt();
1.499 + iLdd->iRxDataAvailableDfc.Add();
1.500 + EndOfInterrupt();
1.501 + }
1.502 +
1.503 +
1.504 +
1.505 +void DCommWins::CompleteRead(TInt aLength)
1.506 + {
1.507 + iReadPending = 0;
1.508 + iInDes.SetLength(aLength);
1.509 + StartOfInterrupt();
1.510 + iLdd->iRxCompleteDfc.Add();
1.511 + EndOfInterrupt();
1.512 + }
1.513 +
1.514 +
1.515 +
1.516 +void DCommWins::DoReadComplete(TInt aErr, TInt aBytes)
1.517 + {
1.518 + iLdd->iRxError = aErr;
1.519 + //write back the length and the data
1.520 + //process for any terminating characters.
1.521 + //win32 only does binary reads and ignores the eofchar, so terminated reads
1.522 + //require reading one char at a time
1.523 + if (iTerminatedRead && !aErr)
1.524 + {
1.525 + __NK_ASSERT_ALWAYS(aBytes <= 1);
1.526 + if (aBytes == 0)
1.527 + {
1.528 + // not sure why we get this somtimes, but handle it anyway : read another character
1.529 + ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped);
1.530 + }
1.531 + else if (++iReadSoFar == iClientReadLength) //see if we have read enough characters into the buffer
1.532 + {
1.533 + //got them all so complete it
1.534 + CompleteRead(iReadSoFar);
1.535 + }
1.536 + else if (IsATerminator(iInBufPtr[iReadSoFar-1])) //see if the char just read was the terminator
1.537 + {
1.538 + //it's a terminated read and we've found one of the terminbators
1.539 + CompleteRead(iReadSoFar);
1.540 + }
1.541 + else if (iReadPending == EReceive)
1.542 + {
1.543 + //read another character
1.544 + ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped);
1.545 + }
1.546 + else
1.547 + {
1.548 + //it's a receive 1 or more with terminators, we've got 1 so that'll do
1.549 + CompleteRead(iReadSoFar);
1.550 + }
1.551 + }
1.552 + else
1.553 + {
1.554 + CompleteRead(aBytes);
1.555 + }
1.556 + }
1.557 +
1.558 +
1.559 +
1.560 +
1.561 +void DCommWins::RunCommThread(TDriverCommand aCommand)
1.562 +//
1.563 +// Wake up the comms thread
1.564 +//
1.565 + {
1.566 +
1.567 + __ASSERT_DEBUG(aCommand!=EInvalidCommand,Panic(EUnknownCommand));
1.568 + iCommand=aCommand;
1.569 +//
1.570 +// Are we about to go re-entrant?
1.571 +//
1.572 + if(GetCurrentThreadId()==iThreadID)
1.573 + {
1.574 + DriverCommand(aCommand);
1.575 + WaitForSingleObject(iDriverThreadSem,INFINITE);
1.576 + }
1.577 + else
1.578 + {
1.579 + Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
1.580 + if (ReleaseSemaphore(iCommThreadSem,1,NULL)==FALSE)
1.581 + {
1.582 + DWORD ret=GetLastError();
1.583 + ret=ret;
1.584 + Panic(EWindowsUnexpectedError);
1.585 + }
1.586 + WaitForSingleObject(iDriverThreadSem,INFINITE);
1.587 + }
1.588 + }
1.589 +
1.590 +inline void DCommWins::SignalDriverThread()
1.591 +//
1.592 +// Wake up the comms thread
1.593 +//
1.594 + {
1.595 + Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
1.596 + if (ReleaseSemaphore(iDriverThreadSem,1,NULL)==FALSE)
1.597 + {
1.598 + DWORD ret=GetLastError();
1.599 + ret=ret;
1.600 + Panic(EWindowsUnexpectedError);
1.601 + }
1.602 + }
1.603 +
1.604 +
1.605 +
1.606 +//
1.607 +#pragma warning( disable : 4705 ) // statement has no effect
1.608 +DCommWins::DCommWins() : iOutDes(0,0), iInDes(0,0), iRxBufferSize(KDefaultWinNTReadBufSize), iSignalsRequested(0)
1.609 + {
1.610 + __DECLARE_NAME(_S("DCommWins"));
1.611 + }
1.612 +#pragma warning( default : 4705 )
1.613 +
1.614 +TInt DCommWins::DoCreate(TInt aUnit,const TDesC8 * /*aInfo*/)
1.615 +//
1.616 +// Create the comms driver.
1.617 +//
1.618 + {
1.619 +
1.620 +#if defined (__COM_ONE_ONLY__)
1.621 + if (aUnit!=0)
1.622 + return KErrNotSupported;
1.623 +#elif defined (__COM_TWO_ONLY__)
1.624 + if (aUnit!=1)
1.625 + return KErrNotSupported;
1.626 +#endif
1.627 +
1.628 + TBuf8<0x10> n;
1.629 + n.Append(KComName);
1.630 + n.AppendNum(aUnit+1);
1.631 + n.Append('\0');
1.632 +
1.633 + iCommPort=CreateFileA((LPCSTR)n.Ptr(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
1.634 + if (iCommPort==INVALID_HANDLE_VALUE)
1.635 + {
1.636 + // Reused code from Emulator::LastError() rather than adding an extra case
1.637 + // to Emulator::LastError() because mapping KErrNotSupported to the returned
1.638 + // FILE_NOT_FOUND is non-intuitive and special to this case only
1.639 + DWORD winErr=GetLastError();
1.640 + switch (winErr)
1.641 + {
1.642 + case ERROR_INVALID_USER_BUFFER:
1.643 + case ERROR_NOT_ENOUGH_MEMORY:
1.644 + case ERROR_INSUFFICIENT_BUFFER:
1.645 + return(KErrNoMemory);
1.646 + case ERROR_ACCESS_DENIED:
1.647 + return(KErrAccessDenied);
1.648 + case ERROR_FILE_NOT_FOUND: // Reflects value returned by
1.649 + return(KErrNotSupported); // corresponding MARM Pdd
1.650 + case ERROR_NOT_SUPPORTED:
1.651 + return(KErrNotSupported);
1.652 + default:
1.653 + return(KErrGeneral);
1.654 + }
1.655 + }
1.656 +
1.657 +
1.658 + //create the buffers.
1.659 + //the buffers need to be as big as the client will ever use. 8mb reserved, but commit less
1.660 + iInBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
1.661 + if (!iInBufPtr)
1.662 + return(Emulator::LastError());
1.663 +
1.664 + //commit the first bit of the buffer
1.665 + if (!VirtualAlloc(iInBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
1.666 + return(Emulator::LastError());
1.667 +
1.668 + iInBufLength = KSerialBufferInitialSize;
1.669 + iInDes.Set(iInBufPtr, 0, iInBufLength);
1.670 +
1.671 + //reserve address space for the output buffer
1.672 + iOutBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
1.673 + if (!iOutBufPtr)
1.674 + return(Emulator::LastError());
1.675 +
1.676 + //commit a smaller region of it
1.677 + if (!VirtualAlloc(iOutBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
1.678 + return(Emulator::LastError());
1.679 +
1.680 + iOutBufLength = KSerialBufferInitialSize;
1.681 + iOutDes.Set(iOutBufPtr, 0, iOutBufLength);
1.682 +
1.683 + DCB dcb;
1.684 + //set the dcb size
1.685 + dcb.DCBlength = sizeof(dcb);
1.686 + if (!GetCommStateP(iCommPort,&dcb))
1.687 + return(Emulator::LastError());
1.688 +
1.689 + EscapeCommFunctionP(iCommPort,0);
1.690 +
1.691 +//
1.692 + if (!SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR|EV_RING))
1.693 + return(Emulator::LastError());
1.694 +
1.695 + if(!SetupComm(iCommPort,KDefaultWinNTReadBufSize,KDefaultWinNTWriteBufSize))
1.696 + return(Emulator::LastError());
1.697 +
1.698 + if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
1.699 + return(Emulator::LastError());
1.700 +
1.701 + if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
1.702 + return(Emulator::LastError());
1.703 +
1.704 +//
1.705 +// The serial port seems to open with the error condition set
1.706 +//
1.707 +
1.708 + DWORD err,res;
1.709 + COMSTAT s;
1.710 + if (ClearCommError(iCommPort,&err,&s)==FALSE)
1.711 + res=GetLastError();
1.712 +
1.713 + if ((iThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)commThread,(void *)this, FALSE))==NULL)
1.714 + return(Emulator::LastError());
1.715 +
1.716 + SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
1.717 + return(KErrNone);
1.718 + }
1.719 +
1.720 +
1.721 +
1.722 +void DCommWins::ReleaseBuffers()
1.723 + {
1.724 + if (iInBufPtr)
1.725 + {
1.726 + //decommit the buffer
1.727 + VirtualFree(iInBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
1.728 + //and release the region
1.729 + VirtualFree(iInBufPtr, NULL, MEM_RELEASE);
1.730 + iInBufPtr = NULL;
1.731 + }
1.732 + if (iOutBufPtr)
1.733 + {
1.734 + VirtualFree(iOutBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
1.735 + VirtualFree(iOutBufPtr, NULL, MEM_RELEASE);
1.736 + iOutBufPtr = NULL;
1.737 + }
1.738 + }
1.739 +
1.740 +
1.741 +DCommWins::~DCommWins()
1.742 + {
1.743 + if (iThread)
1.744 + {
1.745 + if (! iRunning)
1.746 + {
1.747 + __ASSERT_ALWAYS(
1.748 + ResumeThread(iThread) != 0xffffffff,
1.749 + Panic(EWindowsUnexpectedError));
1.750 + }
1.751 +
1.752 + iRunning=ETrue;
1.753 + RunCommThread(EDie);
1.754 + }
1.755 +
1.756 + if (iCommPort)
1.757 + CloseHandle(iCommPort);
1.758 +
1.759 + if (iDriverThreadSem)
1.760 + CloseHandle(iDriverThreadSem);
1.761 +
1.762 + if (iCommThreadSem)
1.763 + CloseHandle(iCommThreadSem);
1.764 +
1.765 + if (iReadOverLapped.hEvent)
1.766 + CloseHandle(iReadOverLapped.hEvent);
1.767 +
1.768 + if (iWriteOverLapped.hEvent)
1.769 + CloseHandle(iWriteOverLapped.hEvent);
1.770 +
1.771 + if (iSignalOverLapped.hEvent)
1.772 + CloseHandle(iSignalOverLapped.hEvent);
1.773 +
1.774 + if (iThread)
1.775 + CloseHandle(iThread);
1.776 +
1.777 + //free up the memory
1.778 + ReleaseBuffers();
1.779 + }
1.780 +
1.781 +TInt DCommWins::Start()
1.782 + {
1.783 +
1.784 + __ASSERT_ALWAYS(ResumeThread(iThread)!=0xffffffff,Panic(EWindowsUnexpectedError));
1.785 + iRunning=ETrue;
1.786 + RunCommThread(EStart);
1.787 + return(KErrNone);
1.788 + }
1.789 +
1.790 +void DCommWins::Stop(TStopMode aMode)
1.791 + {
1.792 +
1.793 + RunCommThread((aMode==EStopEmergency) ? EStopNoDrain : EStop);
1.794 + SuspendThread(iThread);
1.795 + iRunning=EFalse;
1.796 + }
1.797 +
1.798 +void DCommWins::Break(TBool aState)
1.799 +//
1.800 +// Assert a break signal
1.801 +//
1.802 + {
1.803 + if (aState)
1.804 + RunCommThread(ESetBreak);
1.805 + else
1.806 + RunCommThread(EClearBreak);
1.807 + }
1.808 +
1.809 +
1.810 +
1.811 +TInt DCommWins::RxCount()
1.812 + {
1.813 + DWORD err =0;
1.814 + COMSTAT stat;
1.815 + if (ClearCommError(iCommPort,&err, &stat))
1.816 + return stat.cbInQue;
1.817 + else
1.818 + return Emulator::LastError();
1.819 + }
1.820 +
1.821 +
1.822 +void DCommWins::ResetBuffers(TBool aTx)
1.823 + {
1.824 + PurgeComm(iCommPort, PURGE_RXCLEAR | (aTx ? PURGE_TXCLEAR : 0));
1.825 + }
1.826 +
1.827 +
1.828 +TBool DCommWins::AreAnyPending()
1.829 + {
1.830 + return (iReadPending != 0) || (iWritePending != 0);
1.831 + }
1.832 +
1.833 +
1.834 +void DCommWins::WriteCancel()
1.835 + {
1.836 + DriverCommand(ETransmitCancel);
1.837 + }
1.838 +
1.839 +
1.840 +void DCommWins::ReadCancel()
1.841 + {
1.842 + DriverCommand(EReceiveCancel);
1.843 + }
1.844 +
1.845 +void DCommWins::SignalChangeCancel()
1.846 + {
1.847 + if (iSignalsRequested)
1.848 + {
1.849 + iSignalsRequested = 0;
1.850 + }
1.851 +
1.852 + }
1.853 +
1.854 +void DCommWins::DataAvailableNotificationCancel()
1.855 + {
1.856 + if (iDataAvailableNotification)
1.857 + {
1.858 + iDataAvailableNotification = EFalse;
1.859 + iLdd->iRxDAError = KErrCancel;
1.860 + iLdd->iRxDataAvailableDfc.Enque();
1.861 + }
1.862 + }
1.863 +
1.864 +TDes8* DCommWins::RxBuffer()
1.865 + {
1.866 + return &iInDes;
1.867 + }
1.868 +
1.869 +TInt DCommWins::SetRxBufferSize(TInt aSize)
1.870 + {
1.871 + aSize += aSize&1; //round up to multiple of 2 bytes as windows complains if odd
1.872 + TInt ret = SetupComm(iCommPort, aSize, KDefaultWinNTWriteBufSize);
1.873 + if (ret)
1.874 + {
1.875 + iRxBufferSize = aSize;
1.876 +
1.877 + DCB dcb = {0};
1.878 + dcb.DCBlength = sizeof(dcb);
1.879 +
1.880 + if (!GetCommStateP(iCommPort,&dcb))
1.881 + return Emulator::LastError();
1.882 +
1.883 + //use rx buffer size to configure xon/xoff limits
1.884 + dcb.XoffLim = (WORD)(iRxBufferSize / 4); //25%
1.885 + if (iConfig->iParityError & KConfigXonXoffDebug)
1.886 + dcb.XonLim = (WORD)((iRxBufferSize / 2) -5); //50%-5
1.887 + else
1.888 + dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3); //75%
1.889 +
1.890 + if (!SetCommStateP(iCommPort,&dcb))
1.891 + return Emulator::LastError();
1.892 +
1.893 + return KErrNone;
1.894 + }
1.895 + return Emulator::LastError();
1.896 + }
1.897 +
1.898 +
1.899 +TInt DCommWins::RxBufferSize()
1.900 + {
1.901 + return iRxBufferSize;
1.902 + }
1.903 +
1.904 +
1.905 +TBool DCommWins::IsATerminator(TText8 aChar)
1.906 + {
1.907 + TInt x;
1.908 + for (x=0; x < iConfig->iTerminatorCount; x++)
1.909 + if (aChar == iConfig->iTerminator[x])
1.910 + return ETrue;
1.911 + return EFalse;
1.912 + }
1.913 +
1.914 +
1.915 +void DCommWins::ReSizeBuffer(TUint8*& aBuf, TInt& aBufLen, TPtr8& aDes, const TInt aNewLen)
1.916 + {
1.917 +
1.918 + if (aNewLen > KSerialBufferMaxSize)
1.919 + Panic(ESerialBufferTooBig);
1.920 +
1.921 + aBufLen = ((aNewLen + KSerialBufferIncrementSize-1) / KSerialBufferIncrementSize) * KSerialBufferIncrementSize;
1.922 +
1.923 + if (aBufLen > KSerialBufferMaxSize)
1.924 + aBufLen = KSerialBufferMaxSize;
1.925 +
1.926 + if (!VirtualAlloc(aBuf, aBufLen, MEM_COMMIT,PAGE_READWRITE))
1.927 + {
1.928 + ReleaseBuffers();
1.929 + Panic(ESerialBufferTooBig);
1.930 + }
1.931 + aDes.Set(aBuf, 0, aBufLen);
1.932 + }
1.933 +
1.934 +
1.935 +void DCommWins::Write(DThread* aThread, TAny* aSrc, TInt aLength)
1.936 +
1.937 + {
1.938 + if (aLength==0)
1.939 + {
1.940 + RunCommThread(ETransmit0);
1.941 + }
1.942 + else
1.943 + {
1.944 + if (aLength > iOutBufLength)
1.945 + ReSizeBuffer(iOutBufPtr, iOutBufLength, iOutDes, aLength);
1.946 +
1.947 + //copy the data from the client
1.948 + Kern::ThreadDesRead(aThread, aSrc, iOutDes, 0,0);
1.949 + iOutDes.SetLength(aLength);
1.950 + //tell the comms thread to write the data
1.951 + RunCommThread(ETransmit);
1.952 + }
1.953 + }
1.954 +
1.955 +void DCommWins::NotifySignals(DThread* /*aThread*/, TInt aMask)
1.956 + {
1.957 + iSignalsWanted = aMask;
1.958 + RunCommThread(ENotifySignals);
1.959 + }
1.960 +
1.961 +
1.962 +void DCommWins::NotifyDataAvailable()
1.963 + {
1.964 + RunCommThread(ENotifyDataAvailable);
1.965 + }
1.966 +
1.967 +
1.968 +void DCommWins::Read(DThread* /*aThread*/, TAny* /*aDest*/, TInt aLength)
1.969 +
1.970 + {
1.971 + TDriverCommand command;
1.972 +
1.973 + if (aLength < 0)
1.974 + {
1.975 + iClientReadLength = Abs(aLength);
1.976 + command = EReceiveOneOrMore;
1.977 + }
1.978 + else
1.979 + {
1.980 + iClientReadLength = aLength;
1.981 + command = EReceive;
1.982 + }
1.983 +
1.984 + if (iClientReadLength > iInBufLength)
1.985 + ReSizeBuffer(iInBufPtr, iInBufLength, iInDes, iClientReadLength);
1.986 +
1.987 + //tell the comms thread to read the data
1.988 + RunCommThread(command);
1.989 + }
1.990 +
1.991 +
1.992 +
1.993 +
1.994 +
1.995 +TUint DCommWins::Signals() const
1.996 + {
1.997 +
1.998 + ULONG signals=0;
1.999 + GetCommModemStatusP(iCommPort,&signals);
1.1000 + TUint status=0;
1.1001 + if (signals&MS_CTS_ON)
1.1002 + status|=KSignalCTS;
1.1003 + if (signals&MS_DSR_ON)
1.1004 + status|=KSignalDSR;
1.1005 + if (signals&MS_RING_ON)
1.1006 + status|=KSignalRNG;
1.1007 + if (signals&MS_RLSD_ON)
1.1008 + status|=KSignalDCD;
1.1009 + return(status|iSignals);
1.1010 + }
1.1011 +
1.1012 +
1.1013 +void DCommWins::SetSignals(TUint aSetMask,TUint aClearMask)
1.1014 + {
1.1015 + if (aSetMask&KSignalRTS)
1.1016 + {
1.1017 + iSignals|=KSignalRTS;
1.1018 + EscapeCommFunctionP(iCommPort,SETRTS);
1.1019 + }
1.1020 + if (aSetMask&KSignalDTR)
1.1021 + {
1.1022 + iSignals|=KSignalDTR;
1.1023 + EscapeCommFunctionP(iCommPort,SETDTR);
1.1024 + }
1.1025 + if (aClearMask&KSignalRTS)
1.1026 + {
1.1027 + iSignals&=(~KSignalRTS);
1.1028 + EscapeCommFunctionP(iCommPort,CLRRTS);
1.1029 + }
1.1030 + if (aClearMask&KSignalDTR)
1.1031 + {
1.1032 + iSignals&=(~KSignalDTR);
1.1033 + EscapeCommFunctionP(iCommPort,CLRDTR);
1.1034 + }
1.1035 + }
1.1036 +
1.1037 +
1.1038 +
1.1039 +void DCommWins::CheckConfig(TCommConfigV01& /*aConfig*/)
1.1040 + {
1.1041 + // Do nothing
1.1042 + }
1.1043 +
1.1044 +
1.1045 +
1.1046 +void DCommWins::Configure(TCommConfigV01 &aConfig)
1.1047 +//
1.1048 +// Ask comm thread to set up the serial port
1.1049 +//
1.1050 + {
1.1051 +
1.1052 + iConfig=&aConfig;
1.1053 + if (iRunning)
1.1054 + {
1.1055 + RunCommThread(EConfigure);
1.1056 + }
1.1057 + else
1.1058 + {
1.1059 +// iCommand=EConfigure;
1.1060 + DoConfigure();
1.1061 + }
1.1062 + }
1.1063 +
1.1064 +void DCommWins::DoConfigure()
1.1065 +//
1.1066 +// Set up the serial port
1.1067 +//
1.1068 + {
1.1069 +
1.1070 + DCB dcb = {0};
1.1071 + //set the dcb size
1.1072 + dcb.DCBlength = sizeof(dcb);
1.1073 + if (!GetCommStateP(iCommPort,&dcb))
1.1074 + return;
1.1075 +
1.1076 +
1.1077 + //stop if an error happens
1.1078 + dcb.fAbortOnError = TRUE;
1.1079 +
1.1080 + //baud rate
1.1081 + switch (iConfig->iRate)
1.1082 + {
1.1083 + case EBps75:
1.1084 + dcb.BaudRate=75;
1.1085 + break;
1.1086 + case EBps110:
1.1087 + dcb.BaudRate=110;
1.1088 + break;
1.1089 + case EBps134:
1.1090 + dcb.BaudRate=134;
1.1091 + break;
1.1092 + case EBps150:
1.1093 + dcb.BaudRate=150;
1.1094 + break;
1.1095 + case EBps300:
1.1096 + dcb.BaudRate=300;
1.1097 + break;
1.1098 + case EBps600:
1.1099 + dcb.BaudRate=600;
1.1100 + break;
1.1101 + case EBps1200:
1.1102 + dcb.BaudRate=1200;
1.1103 + break;
1.1104 + case EBps1800:
1.1105 + dcb.BaudRate=1800;
1.1106 + break;
1.1107 + case EBps2400:
1.1108 + dcb.BaudRate=2400;
1.1109 + break;
1.1110 + case EBps4800:
1.1111 + dcb.BaudRate=4800;
1.1112 + break;
1.1113 + case EBps7200:
1.1114 + dcb.BaudRate=7200;
1.1115 + break;
1.1116 + case EBps9600:
1.1117 + dcb.BaudRate=9600;
1.1118 + break;
1.1119 + case EBps19200:
1.1120 + dcb.BaudRate=19200;
1.1121 + break;
1.1122 + case EBps38400:
1.1123 + dcb.BaudRate=38400;
1.1124 + break;
1.1125 + case EBps57600:
1.1126 + dcb.BaudRate=57600;
1.1127 + break;
1.1128 + case EBps115200:
1.1129 + dcb.BaudRate=115200;
1.1130 + break;
1.1131 + }
1.1132 +
1.1133 + switch (iConfig->iParity)
1.1134 + {
1.1135 + case EParityNone:
1.1136 + dcb.Parity=NOPARITY;
1.1137 + dcb.fParity = FALSE;
1.1138 + break;
1.1139 + case EParityEven:
1.1140 + dcb.Parity=EVENPARITY;
1.1141 + dcb.fParity = TRUE;
1.1142 + break;
1.1143 + case EParityOdd:
1.1144 + dcb.Parity=ODDPARITY;
1.1145 + dcb.fParity = TRUE;
1.1146 + break;
1.1147 + case EParityMark:
1.1148 + dcb.Parity = MARKPARITY;
1.1149 + dcb.fParity = TRUE;
1.1150 + break;
1.1151 + case EParitySpace:
1.1152 + dcb.Parity = SPACEPARITY;
1.1153 + dcb.fParity = TRUE;
1.1154 + break;
1.1155 + }
1.1156 +
1.1157 + switch (iConfig->iParityError)
1.1158 + {
1.1159 + case KConfigParityErrorFail:
1.1160 + dcb.fErrorChar = FALSE;
1.1161 + break;
1.1162 +
1.1163 + case KConfigParityErrorIgnore:
1.1164 + dcb.fErrorChar = FALSE;
1.1165 + dcb.fAbortOnError = FALSE;
1.1166 + break;
1.1167 +
1.1168 + case KConfigParityErrorReplaceChar:
1.1169 + dcb.fErrorChar = TRUE;
1.1170 + dcb.ErrorChar = iConfig->iParityErrorChar;
1.1171 + break;
1.1172 + }
1.1173 +
1.1174 +
1.1175 + TUint& hs = iConfig->iHandshake;
1.1176 +
1.1177 +
1.1178 + //SOFTWARE FLOW CONTROL
1.1179 + dcb.fInX = (hs & KConfigObeyXoff) ? TRUE : FALSE;
1.1180 + dcb.fOutX = (hs & KConfigSendXoff) ? TRUE : FALSE;
1.1181 +
1.1182 + dcb.XonChar = iConfig->iXonChar;
1.1183 + dcb.XoffChar = iConfig->iXoffChar;
1.1184 + dcb.ErrorChar = iConfig->iParityErrorChar;
1.1185 +
1.1186 + //use rx buffer size to configure xon/xoff limits
1.1187 + dcb.XoffLim = (WORD)(iRxBufferSize / 4); //25%
1.1188 + if (iConfig->iParityError & KConfigXonXoffDebug)
1.1189 + dcb.XonLim = (WORD)((iRxBufferSize / 2) -5); //50%-5
1.1190 + else
1.1191 + dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3); //75%
1.1192 +
1.1193 +
1.1194 +
1.1195 + //OUTPUT HARDWARE FLOW CONTROL
1.1196 + //set out DSR control to be off
1.1197 + dcb.fOutxDsrFlow = FALSE;
1.1198 + dcb.fOutxCtsFlow = (hs & KConfigObeyCTS) ? TRUE : FALSE;
1.1199 + dcb.fDsrSensitivity = (hs & KConfigObeyDSR) ? TRUE : FALSE;
1.1200 +
1.1201 +
1.1202 + if (hs & KConfigObeyDCD)
1.1203 + {
1.1204 + }
1.1205 +
1.1206 +
1.1207 + //INPUT HARDWARE FLOW CONTROL
1.1208 + dcb.fRtsControl = (hs & KConfigFreeRTS) ? RTS_CONTROL_DISABLE : RTS_CONTROL_HANDSHAKE;
1.1209 + dcb.fDtrControl = (hs & KConfigFreeDTR) ? DTR_CONTROL_DISABLE : DTR_CONTROL_ENABLE;
1.1210 +
1.1211 +
1.1212 + //complete with KErrCommsLineFail if these are set and the line goes low
1.1213 + iFailSignals = 0;
1.1214 + if (hs & KConfigFailDSR)
1.1215 + iFailSignals |= KSignalDSR;
1.1216 +
1.1217 + if (hs & KConfigFailCTS)
1.1218 + iFailSignals |= KSignalCTS;
1.1219 +
1.1220 + if (hs & KConfigFailDCD)
1.1221 + iFailSignals |= KSignalDCD;
1.1222 +
1.1223 +
1.1224 + iTerminatedRead = iConfig->iTerminatorCount > 0;
1.1225 +
1.1226 + switch(iConfig->iDataBits)
1.1227 + {
1.1228 + case EData5:
1.1229 + dcb.ByteSize=5;
1.1230 + break;
1.1231 + case EData6:
1.1232 + dcb.ByteSize=6;
1.1233 + break;
1.1234 + case EData7:
1.1235 + dcb.ByteSize=7;
1.1236 + break;
1.1237 + case EData8:
1.1238 + dcb.ByteSize=8;
1.1239 + break;
1.1240 + }
1.1241 +
1.1242 + switch(iConfig->iStopBits)
1.1243 + {
1.1244 + case EStop1:
1.1245 + dcb.StopBits=ONESTOPBIT;
1.1246 + break;
1.1247 + case EStop2:
1.1248 + dcb.StopBits=TWOSTOPBITS;
1.1249 + break;
1.1250 + }
1.1251 +
1.1252 +
1.1253 +
1.1254 + TInt error_r=KErrNone;
1.1255 + if(!SetCommStateP(iCommPort,&dcb))
1.1256 + error_r=GetLastError();
1.1257 +
1.1258 +// Clear any error we may have caused
1.1259 +//
1.1260 + DWORD err,res;
1.1261 + COMSTAT s;
1.1262 + if (ClearCommError(iCommPort,&err,&s)==FALSE)
1.1263 + res=GetLastError();
1.1264 +
1.1265 + }
1.1266 +
1.1267 +void DCommWins::Caps(TDes8 &aCaps) const
1.1268 +//
1.1269 +// Return the current capabilities
1.1270 +//
1.1271 + {
1.1272 +
1.1273 + GetWinsCommsCaps(aCaps);
1.1274 + }
1.1275 +
1.1276 +
1.1277 +void DCommWins::WaitForEvent()
1.1278 + {
1.1279 +
1.1280 + HANDLE objects[4];
1.1281 +
1.1282 +
1.1283 + iReadOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
1.1284 + iWriteOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
1.1285 + iSignalOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
1.1286 + objects[0]=iSignalOverLapped.hEvent; // iCommPort;
1.1287 + objects[1]=iCommThreadSem;
1.1288 + objects[2]=iWriteOverLapped.hEvent;
1.1289 + objects[3]=iReadOverLapped.hEvent;
1.1290 +
1.1291 + FOREVER
1.1292 + {
1.1293 + DWORD ret=WaitForMultipleObjectsEx(4,objects,FALSE,INFINITE,TRUE);
1.1294 + switch (ret)
1.1295 + {
1.1296 + case WAIT_OBJECT_0:
1.1297 + {
1.1298 + // EnterCritical();
1.1299 +
1.1300 + if (iDataAvailableNotification)
1.1301 + {
1.1302 + DataAvailableCompletion(this);
1.1303 + iDataAvailableNotification = EFalse; //stop us repeatedly reporting it
1.1304 + }
1.1305 +
1.1306 + // Detect breaks
1.1307 + if (iSignalStatus & EV_BREAK)
1.1308 + {
1.1309 + iBreakDetected=ETrue; // the read will complete with an error
1.1310 + }
1.1311 +
1.1312 + TUint currentSignals = Signals();
1.1313 +
1.1314 + //mask out all the signals but the ones we are interested in
1.1315 + iLineFail = (iFailSignals & currentSignals) != iFailSignals;
1.1316 + if (iLineFail)
1.1317 + {
1.1318 + //if we have the handshake options of
1.1319 + //KConfigFailDSR, KConfigFailDCD KFailConfigCTS set
1.1320 + //we need to do something if any of them are low so
1.1321 + //complete any outstanding ops with failure
1.1322 + if (iReadPending)
1.1323 + {
1.1324 + //we have a read to complete
1.1325 + iRXLineFail = ETrue;
1.1326 + PurgeComm(iCommPort, PURGE_RXABORT);
1.1327 + }
1.1328 +
1.1329 + if (iWritePending)
1.1330 + {
1.1331 + //we have a write to complete
1.1332 + iTXLineFail = ETrue;
1.1333 + PurgeComm(iCommPort, PURGE_TXABORT);
1.1334 + }
1.1335 + }
1.1336 +
1.1337 +
1.1338 + //iSignalsRequested will only have bits set if outstanding request
1.1339 + TUint changed = (currentSignals ^ iSavedSignals) & iSignalsRequested;
1.1340 + if (changed)
1.1341 + {
1.1342 + SignalCompletion(this, KErrNone, changed, currentSignals);
1.1343 + iSavedSignals = currentSignals;
1.1344 + iSignalsRequested = 0; //stop us repeatedly reporting it.
1.1345 + //iSignalsRequested is setup in the call to notify
1.1346 + }
1.1347 +
1.1348 + if (iWritePending == ETransmit0 && (currentSignals & KSignalCTS) != 0)
1.1349 + WriteCompletion(this, KErrNone, 0);
1.1350 +
1.1351 + //request another notification event. All events are requested.
1.1352 + iSignalStatus=0;
1.1353 + DWORD commErrors;
1.1354 + BOOL res;
1.1355 + DWORD lastError = 0;
1.1356 + COMSTAT cstat;
1.1357 +
1.1358 + do
1.1359 + {
1.1360 + ClearCommError(iCommPort,&commErrors,&cstat);
1.1361 + res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
1.1362 + if (!res)
1.1363 + lastError = GetLastError();
1.1364 + }
1.1365 + while((!res) && (lastError != ERROR_IO_PENDING));
1.1366 +
1.1367 + break;
1.1368 + }
1.1369 +
1.1370 + case WAIT_OBJECT_0+1:
1.1371 +//
1.1372 +// iCommThreadSemaphore has been signalled
1.1373 +//
1.1374 + DriverCommand(iCommand);
1.1375 + break;
1.1376 + case WAIT_OBJECT_0+2:
1.1377 + //
1.1378 + // Write completion
1.1379 + //
1.1380 + {
1.1381 +
1.1382 + DWORD len = 0;
1.1383 + TInt error = KErrNone;
1.1384 + if (!GetOverlappedResult(iCommPort, &iWriteOverLapped, &len, FALSE))
1.1385 + error = Emulator::LastError();
1.1386 +
1.1387 + COMSTAT s;
1.1388 + DWORD err = 0;
1.1389 + ClearCommError(iCommPort,&err,&s);
1.1390 +
1.1391 + //if we are failing if one or more of CTS, DSR, DCD go low
1.1392 + if (iTXLineFail)
1.1393 + {
1.1394 + error = KErrCommsLineFail;
1.1395 + iTXLineFail = EFalse;
1.1396 + }
1.1397 + else if (err)
1.1398 + {
1.1399 + if (err & CE_FRAME)
1.1400 + error = KErrCommsFrame;
1.1401 + else if (err & CE_OVERRUN)
1.1402 + error = KErrCommsOverrun;
1.1403 + else if (err & CE_RXPARITY)
1.1404 + error = KErrCommsParity;
1.1405 + }
1.1406 +
1.1407 + WriteCompletion(this, error, len);
1.1408 + break;
1.1409 + }
1.1410 +
1.1411 + case WAIT_OBJECT_0+3:
1.1412 + //
1.1413 + // Read completion
1.1414 + //
1.1415 + {
1.1416 + DWORD len = 0;
1.1417 + TInt error = KErrNone;
1.1418 + if (!GetOverlappedResult(iCommPort, &iReadOverLapped, &len, FALSE))
1.1419 + {
1.1420 + // May have a break already detected to report
1.1421 + if (iBreakDetected)
1.1422 + {
1.1423 + error=KErrCommsBreak;
1.1424 + iBreakDetected=EFalse;
1.1425 + }
1.1426 + else
1.1427 + error = Emulator::LastError();
1.1428 + }
1.1429 + else
1.1430 + iBreakDetected=EFalse; // No error, so any breaks have finished
1.1431 +
1.1432 + COMSTAT s;
1.1433 + DWORD err = 0;
1.1434 + ClearCommError(iCommPort,&err,&s);
1.1435 +
1.1436 + //if we are failing if one or more of CTS, DSR, DCD go low
1.1437 + if (iRXLineFail)
1.1438 + {
1.1439 + error = KErrCommsLineFail;
1.1440 + iRXLineFail = EFalse;
1.1441 + }
1.1442 + else if (err)
1.1443 + {
1.1444 + if (err & CE_FRAME)
1.1445 + error = KErrCommsFrame;
1.1446 + else if (err & CE_OVERRUN)
1.1447 + error = KErrCommsOverrun;
1.1448 + else if (err & CE_RXPARITY)
1.1449 + error = KErrCommsParity;
1.1450 + }
1.1451 +
1.1452 + ReadCompletion(this, error, len);
1.1453 + break;
1.1454 + }
1.1455 +
1.1456 + case WAIT_IO_COMPLETION:
1.1457 + break;
1.1458 +
1.1459 + default:
1.1460 + Emulator::LastError();
1.1461 + FAULT();
1.1462 + }
1.1463 + }
1.1464 + }
1.1465 +
1.1466 +void DCommWins::DriverCommand(TDriverCommand aCommand)
1.1467 +//
1.1468 +// Do a driver command - executed when the semaphore has been signalled in the comm port thread
1.1469 +//
1.1470 + {
1.1471 + switch (aCommand)
1.1472 + {
1.1473 + case ESetBreak:
1.1474 + FlushFileBuffers(iCommPort);
1.1475 + SetCommBreak(iCommPort);
1.1476 + break;
1.1477 +
1.1478 + case EClearBreak:
1.1479 + ClearCommBreak(iCommPort);
1.1480 + break;
1.1481 +
1.1482 + case ETransmit0:
1.1483 +
1.1484 + if (!iWritePending)
1.1485 + {
1.1486 + if ((iConfig->iHandshake & KConfigObeyCTS) != 0 && (Signals() & KSignalCTS) == 0)
1.1487 + iWritePending = ETransmit0;
1.1488 + else
1.1489 + DoWriteComplete(KErrNone);
1.1490 + }
1.1491 + break;
1.1492 +
1.1493 + case ETransmit:
1.1494 +
1.1495 + if (!iWritePending)
1.1496 + {
1.1497 + COMMTIMEOUTS ct;
1.1498 + int r = GetCommTimeouts(iCommPort, &ct);
1.1499 + ct.WriteTotalTimeoutConstant = 0;
1.1500 + ct.WriteTotalTimeoutMultiplier = 0;
1.1501 + r = SetCommTimeouts(iCommPort, &ct);
1.1502 +
1.1503 + WriteFileP(iCommPort,iOutDes.Ptr(), iOutDes.Length(), &dummyLen, &iWriteOverLapped);
1.1504 + iWritePending = ETransmit;
1.1505 + iTransmitting= ETrue;
1.1506 + }
1.1507 + break;
1.1508 +
1.1509 + case EStart:
1.1510 + {
1.1511 + iSignalStatus=0;
1.1512 + iSignalStatus=0;
1.1513 + DWORD commErrors;
1.1514 + BOOL res;
1.1515 + DWORD lastError = 0;
1.1516 + COMSTAT cstat;
1.1517 +
1.1518 + do
1.1519 + {
1.1520 + ClearCommError(iCommPort,&commErrors,&cstat);
1.1521 + res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
1.1522 + if (!res)
1.1523 + lastError = GetLastError();
1.1524 + }
1.1525 + while((!res) && (lastError != ERROR_IO_PENDING));
1.1526 + }
1.1527 + break;
1.1528 +
1.1529 + case EStop:
1.1530 + // Flush last write
1.1531 + if(iWritePending == ETransmit)
1.1532 + {
1.1533 + WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
1.1534 + FlushFileBuffers(iCommPort);
1.1535 + }
1.1536 + iWritePending=0;
1.1537 + iTransmitting=EFalse;
1.1538 + // Fall through
1.1539 + case EStopNoDrain:
1.1540 + // Cancel any pending writes
1.1541 + if(iWritePending == ETransmit)
1.1542 + {
1.1543 + PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
1.1544 + WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
1.1545 + }
1.1546 + iWritePending=0;
1.1547 + iTransmitting=EFalse;
1.1548 + iStopping=ETrue;
1.1549 + if(iRunning)
1.1550 + {
1.1551 + SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR);
1.1552 + WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
1.1553 + }
1.1554 + break;
1.1555 +
1.1556 + case EDie:
1.1557 + SignalDriverThread();
1.1558 + ExitThread(1);
1.1559 + break;
1.1560 +
1.1561 + case EConfigure:
1.1562 + DoConfigure();
1.1563 + break;
1.1564 +
1.1565 + case ETransmitCancel:
1.1566 + if (iWritePending == ETransmit)
1.1567 + PurgeComm(iCommPort, PURGE_TXABORT);
1.1568 +// else if (iWritePending == ETransmit0)
1.1569 +// {
1.1570 + // careful - this runs in the context of the kernel thread, not the event thread
1.1571 + iLdd->iTxError = KErrCancel;
1.1572 + iLdd->iTxCompleteDfc.Enque();
1.1573 +// }
1.1574 + break;
1.1575 +
1.1576 + case EReceive:
1.1577 + if (!iReadPending)
1.1578 + {
1.1579 + COMMTIMEOUTS ct;
1.1580 + int r = GetCommTimeouts(iCommPort, &ct);
1.1581 + ct.ReadIntervalTimeout = 0;
1.1582 + ct.ReadTotalTimeoutMultiplier = 0;
1.1583 + ct.ReadTotalTimeoutConstant = 0;
1.1584 + r = SetCommTimeouts(iCommPort, &ct);
1.1585 +
1.1586 + //if we are doing a terminated read.... we need to do it a byte at a time!
1.1587 + if (iTerminatedRead)
1.1588 + {
1.1589 + iReadSoFar = 0;
1.1590 + ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped);
1.1591 + }
1.1592 + else
1.1593 + {
1.1594 + ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
1.1595 + }
1.1596 +
1.1597 + iReadPending = EReceive;
1.1598 + }
1.1599 + break;
1.1600 +
1.1601 + case EReceiveOneOrMore:
1.1602 + if (!iReadPending)
1.1603 + {
1.1604 + COMMTIMEOUTS ct;
1.1605 + int r = GetCommTimeouts(iCommPort, &ct);
1.1606 + ct.ReadIntervalTimeout = MAXDWORD;
1.1607 + ct.ReadTotalTimeoutMultiplier = MAXDWORD;
1.1608 + ct.ReadTotalTimeoutConstant = KReadOneOrMoreTimeout;
1.1609 + r = SetCommTimeouts(iCommPort, &ct);
1.1610 +
1.1611 + //if we are doing a terminated read....
1.1612 + if (iTerminatedRead)
1.1613 + {
1.1614 + iReadSoFar = 0;
1.1615 + ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped);
1.1616 + }
1.1617 + else
1.1618 + {
1.1619 + ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
1.1620 + }
1.1621 +
1.1622 + iReadPending = EReceiveOneOrMore;
1.1623 + }
1.1624 + break;
1.1625 +
1.1626 + case EReceiveCancel:
1.1627 + if (iReadPending)
1.1628 + PurgeComm(iCommPort, PURGE_RXABORT);
1.1629 + else if (iDataAvailableNotification)
1.1630 + DataAvailableNotificationCancel();
1.1631 + break;
1.1632 +
1.1633 + case ENotifyDataAvailable:
1.1634 + {
1.1635 + iDataAvailableNotification = ETrue;
1.1636 + //setup the comms notifications for data available
1.1637 + break;
1.1638 + }
1.1639 +
1.1640 + case ENotifySignals:
1.1641 + {
1.1642 + TUint currentSignals = Signals();
1.1643 + TUint changed = (currentSignals ^ iSavedSignals) & iSignalsWanted;
1.1644 + if (changed)
1.1645 + {
1.1646 + SignalCompletion(this, KErrNone, changed, currentSignals);
1.1647 + iSavedSignals = currentSignals;
1.1648 + iSignalsWanted = 0;
1.1649 + }
1.1650 + else
1.1651 + iSignalsRequested = iSignalsWanted; //checked when signals change
1.1652 + }
1.1653 + break;
1.1654 +
1.1655 +
1.1656 + default:
1.1657 + // Panic(EUnknownCommand);
1.1658 + break;
1.1659 + }
1.1660 + iCommand=EInvalidCommand;
1.1661 + SignalDriverThread();
1.1662 + }
1.1663 +
1.1664 +
1.1665 +TDfcQue* DCommWins::DfcQ(TInt /*aUnit*/)
1.1666 + {
1.1667 + return Kern::DfcQue0();
1.1668 + }
1.1669 +
1.1670 +
1.1671 +TInt DCommWins::ValidateConfig(const TCommConfigV01 &aConfig) const
1.1672 +//
1.1673 +// Check a config structure.
1.1674 +//
1.1675 + {
1.1676 + if(aConfig.iRate & EBpsSpecial)
1.1677 + return KErrNotSupported;
1.1678 +
1.1679 + switch (aConfig.iParity)
1.1680 + {
1.1681 + case EParityNone:
1.1682 + case EParityOdd:
1.1683 + case EParityEven:
1.1684 + break;
1.1685 + default:
1.1686 + return KErrNotSupported;
1.1687 + }
1.1688 + switch (aConfig.iRate)
1.1689 + {
1.1690 + case EBps50:
1.1691 + case EBps75:
1.1692 + case EBps134:
1.1693 + case EBps1800:
1.1694 + case EBps2000:
1.1695 + case EBps3600:
1.1696 + case EBps7200:
1.1697 + return KErrNotSupported;
1.1698 + default:
1.1699 + break;
1.1700 + };
1.1701 + return KErrNone;
1.1702 + }
1.1703 +
1.1704 +inline TBool DCommWins::LineFail()
1.1705 + {
1.1706 + return iLineFail;
1.1707 + }
1.1708 +
1.1709 +
1.1710 +
1.1711 +DECLARE_STANDARD_PDD()
1.1712 + {
1.1713 + return new DDriverComm;
1.1714 + }
1.1715 +