First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // wins/specific/serialpdd.cpp
23 #define WIN32_LEAN_AND_MEAN
24 #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
26 #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
31 #define FAULT() Kern::Fault(__FILE__,__LINE__)
33 _LIT(KComName, "\\\\.\\com");
35 // needs ldd version..
36 const TInt KMinimumLddMajorVersion=1;
37 const TInt KMinimumLddMinorVersion=1;
38 const TInt KMinimumLddBuild=1;
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
47 const DWORD KReadOneOrMoreTimeout = MAXDWORD-1; //milliseconds
50 //buffer sizes passed to NT for setting its own driver buffer sizes
51 const TInt KDefaultWinNTReadBufSize = 1024;
52 const TInt KDefaultWinNTWriteBufSize = 1024;
54 static DWORD dummyLen=0;
58 EWindowsUnexpectedError,
62 EWriteEarlyCompletion,
63 ELineErrorNotReported,
69 class DDriverComm : public DPhysicalDevice
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);
81 class DCommWins : public DComm
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};
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);
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);
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();
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();
143 TDriverCommand iCommand;
144 TCommConfigV01 *iConfig;
152 TUint8 * iInBufPtr; //input buffer used by driver.
157 TBool iTerminatedRead; //true if we are reading with 1 or more terminating characters
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;
169 HANDLE iCommThreadSem;
170 HANDLE iDriverThreadSem;
174 OVERLAPPED iReadOverLapped;
175 OVERLAPPED iWriteOverLapped;
176 OVERLAPPED iSignalOverLapped;
178 TInt iClientReadLength; //how much data the client has requested in a read
179 TBool iBreakDetected;
182 void Panic(TDCommWinsFault aFault)
187 Kern::PanicCurrentThread(_L("DCommWins"), aFault);
191 TUint commThread(DCommWins *comm)
193 // Comm thread entry point
197 comm->WaitForEvent();
201 VOID WINAPI WriteCompletion(DCommWins *aDrv, DWORD aErr,DWORD /*numBytes*/)
204 aDrv->DoWriteComplete(aErr);
208 VOID WINAPI ReadCompletion(DCommWins *aDrv, DWORD aErr,DWORD numBytes)
211 aDrv->DoReadComplete(aErr, numBytes);
214 VOID WINAPI SignalCompletion(DCommWins *aDrv, TInt aError, TUint aChanged, TUint aValues)
216 aDrv->DoSignalCompletion(aError, aChanged, aValues);
219 VOID WINAPI DataAvailableCompletion(DCommWins *aDrv)
221 aDrv->DoDataAvailableCompletion();
226 BOOL WINAPI EscapeCommFunctionP(HANDLE hFile,DWORD dwFunc)
235 ClearCommError(hFile, &err, &s);
236 res = EscapeCommFunction(hFile,dwFunc);
238 lastError = GetLastError();
240 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
246 BOOL WINAPI GetCommModemStatusP(HANDLE hFile,LPDWORD lpModemStat)
255 ClearCommError(hFile, &err, &s);
256 res = GetCommModemStatus(hFile,lpModemStat);
258 lastError = GetLastError();
260 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
266 BOOL WINAPI GetCommStateP(HANDLE hFile,LPDCB lpDCB)
275 ClearCommError(hFile,&err,&s);
276 res = GetCommState(hFile,lpDCB);
278 lastError = GetLastError();
280 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
285 BOOL WINAPI SetCommStateP(HANDLE hFile,LPDCB lpDCB)
294 ClearCommError(hFile, &err, &s);
295 res = SetCommState(hFile, lpDCB);
297 lastError = GetLastError();
299 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
304 BOOL WINAPI SetCommMaskP(HANDLE hFile,DWORD dwEvtMask)
313 ClearCommError(hFile, &err, &s);
314 res = SetCommMask(hFile, dwEvtMask);
316 lastError = GetLastError();
318 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
323 BOOL WINAPI WriteFileP(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)
332 ClearCommError(hFile, &err, &s);
333 res = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
335 lastError = GetLastError();
337 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
342 BOOL WINAPI ReadFileP(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
351 ClearCommError(hFile, &err, &s);
352 res = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
354 lastError = GetLastError();
356 while((!res) && (lastError == ERROR_OPERATION_ABORTED));
364 DDriverComm::DDriverComm()
366 #if defined (__COM_ONE_ONLY__)
367 iUnitsMask=0x1; // Support units 0
368 #elif defined (__COM_TWO_ONLY__)
369 iUnitsMask=0x2; // Support units 1
371 iUnitsMask=0x3ff; // Support units 0 to 9
374 iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
377 TInt DDriverComm::Install()
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));
386 TPtrC buf=_L("Comm.Wins");
387 return(SetName(&buf));
391 TInt DDriverComm::Remove()
397 TInt DDriverComm::Validate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
399 // Validate the requested configuration
402 if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
403 return KErrNotSupported;
404 #if defined (__COM_ONE_ONLY__)
406 return KErrNotSupported;
407 #elif defined (__COM_TWO_ONLY__)
409 return KErrNotSupported;
411 // leave Unit check to CreateFile
416 void GetWinsCommsCaps(TDes8 &aCaps)
419 TCommCapsV03 &c=capsBuf();
421 // All rates except 50,2000, 3600 and special
423 c.iRate=KCapsBps75|KCapsBps110|KCapsBps134|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps1800|KCapsBps2400|KCapsBps4800|KCapsBps7200|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200;
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
431 c.iNotificationCaps=KNotifySignalsChangeSupported|KNotifyDataAvailableSupported;
433 c.iFlowControlCaps=0;
434 c.iBreakSupported=ETrue;
435 aCaps.FillZ(aCaps.MaxLength());
436 aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
439 void DDriverComm::GetCaps(TDes8 &aDes) const
441 GetWinsCommsCaps(aDes);
444 TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit,const TDesC8* aInfo,const TVersion& aVer)
447 if (!Kern::QueryVersionSupported(iVersion,aVer))
448 return KErrNotSupported;
450 DCommWins *pD= new DCommWins;
451 if (!pD) return KErrNoMemory;
453 TInt ret=pD->DoCreate(aUnit,aInfo);
466 void DCommWins::DoWriteComplete(TInt aErr)
469 iTransmitting = EFalse;
471 iLdd->iTxError = aErr;
472 iLdd->iTxCompleteDfc.Add();
478 void DCommWins::DoSignalCompletion(TInt aError, TUint aChanged, TUint aValues)
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);
486 iLdd->iSignalResult = res;
487 iLdd->iSignalError = aError;
489 iLdd->iSigNotifyDfc.Add();
493 void DCommWins::DoDataAvailableCompletion()
496 iLdd->iRxDataAvailableDfc.Add();
502 void DCommWins::CompleteRead(TInt aLength)
505 iInDes.SetLength(aLength);
507 iLdd->iRxCompleteDfc.Add();
513 void DCommWins::DoReadComplete(TInt aErr, TInt aBytes)
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)
522 __NK_ASSERT_ALWAYS(aBytes <= 1);
525 // not sure why we get this somtimes, but handle it anyway : read another character
526 ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped);
528 else if (++iReadSoFar == iClientReadLength) //see if we have read enough characters into the buffer
530 //got them all so complete it
531 CompleteRead(iReadSoFar);
533 else if (IsATerminator(iInBufPtr[iReadSoFar-1])) //see if the char just read was the terminator
535 //it's a terminated read and we've found one of the terminbators
536 CompleteRead(iReadSoFar);
538 else if (iReadPending == EReceive)
540 //read another character
541 ReadFileP(iCommPort,(void*)(iInBufPtr+iReadSoFar), 1, &dummyLen, &iReadOverLapped);
545 //it's a receive 1 or more with terminators, we've got 1 so that'll do
546 CompleteRead(iReadSoFar);
551 CompleteRead(aBytes);
558 void DCommWins::RunCommThread(TDriverCommand aCommand)
560 // Wake up the comms thread
564 __ASSERT_DEBUG(aCommand!=EInvalidCommand,Panic(EUnknownCommand));
567 // Are we about to go re-entrant?
569 if(GetCurrentThreadId()==iThreadID)
571 DriverCommand(aCommand);
572 WaitForSingleObject(iDriverThreadSem,INFINITE);
576 Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
577 if (ReleaseSemaphore(iCommThreadSem,1,NULL)==FALSE)
579 DWORD ret=GetLastError();
581 Panic(EWindowsUnexpectedError);
583 WaitForSingleObject(iDriverThreadSem,INFINITE);
587 inline void DCommWins::SignalDriverThread()
589 // Wake up the comms thread
592 Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
593 if (ReleaseSemaphore(iDriverThreadSem,1,NULL)==FALSE)
595 DWORD ret=GetLastError();
597 Panic(EWindowsUnexpectedError);
604 #pragma warning( disable : 4705 ) // statement has no effect
605 DCommWins::DCommWins() : iOutDes(0,0), iInDes(0,0), iRxBufferSize(KDefaultWinNTReadBufSize), iSignalsRequested(0)
607 __DECLARE_NAME(_S("DCommWins"));
609 #pragma warning( default : 4705 )
611 TInt DCommWins::DoCreate(TInt aUnit,const TDesC8 * /*aInfo*/)
613 // Create the comms driver.
617 #if defined (__COM_ONE_ONLY__)
619 return KErrNotSupported;
620 #elif defined (__COM_TWO_ONLY__)
622 return KErrNotSupported;
627 n.AppendNum(aUnit+1);
630 iCommPort=CreateFileA((LPCSTR)n.Ptr(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
631 if (iCommPort==INVALID_HANDLE_VALUE)
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();
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);
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);
659 return(Emulator::LastError());
661 //commit the first bit of the buffer
662 if (!VirtualAlloc(iInBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
663 return(Emulator::LastError());
665 iInBufLength = KSerialBufferInitialSize;
666 iInDes.Set(iInBufPtr, 0, iInBufLength);
668 //reserve address space for the output buffer
669 iOutBufPtr = (TUint8*)VirtualAlloc(NULL, KSerialBufferMaxSize,MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
671 return(Emulator::LastError());
673 //commit a smaller region of it
674 if (!VirtualAlloc(iOutBufPtr, KSerialBufferInitialSize, MEM_COMMIT,PAGE_READWRITE))
675 return(Emulator::LastError());
677 iOutBufLength = KSerialBufferInitialSize;
678 iOutDes.Set(iOutBufPtr, 0, iOutBufLength);
682 dcb.DCBlength = sizeof(dcb);
683 if (!GetCommStateP(iCommPort,&dcb))
684 return(Emulator::LastError());
686 EscapeCommFunctionP(iCommPort,0);
689 if (!SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR|EV_RING))
690 return(Emulator::LastError());
692 if(!SetupComm(iCommPort,KDefaultWinNTReadBufSize,KDefaultWinNTWriteBufSize))
693 return(Emulator::LastError());
695 if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
696 return(Emulator::LastError());
698 if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
699 return(Emulator::LastError());
702 // The serial port seems to open with the error condition set
707 if (ClearCommError(iCommPort,&err,&s)==FALSE)
710 if ((iThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)commThread,(void *)this, FALSE))==NULL)
711 return(Emulator::LastError());
713 SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
719 void DCommWins::ReleaseBuffers()
723 //decommit the buffer
724 VirtualFree(iInBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
725 //and release the region
726 VirtualFree(iInBufPtr, NULL, MEM_RELEASE);
731 VirtualFree(iOutBufPtr,KSerialBufferMaxSize, MEM_DECOMMIT);
732 VirtualFree(iOutBufPtr, NULL, MEM_RELEASE);
738 DCommWins::~DCommWins()
745 ResumeThread(iThread) != 0xffffffff,
746 Panic(EWindowsUnexpectedError));
754 CloseHandle(iCommPort);
756 if (iDriverThreadSem)
757 CloseHandle(iDriverThreadSem);
760 CloseHandle(iCommThreadSem);
762 if (iReadOverLapped.hEvent)
763 CloseHandle(iReadOverLapped.hEvent);
765 if (iWriteOverLapped.hEvent)
766 CloseHandle(iWriteOverLapped.hEvent);
768 if (iSignalOverLapped.hEvent)
769 CloseHandle(iSignalOverLapped.hEvent);
772 CloseHandle(iThread);
778 TInt DCommWins::Start()
781 __ASSERT_ALWAYS(ResumeThread(iThread)!=0xffffffff,Panic(EWindowsUnexpectedError));
783 RunCommThread(EStart);
787 void DCommWins::Stop(TStopMode aMode)
790 RunCommThread((aMode==EStopEmergency) ? EStopNoDrain : EStop);
791 SuspendThread(iThread);
795 void DCommWins::Break(TBool aState)
797 // Assert a break signal
801 RunCommThread(ESetBreak);
803 RunCommThread(EClearBreak);
808 TInt DCommWins::RxCount()
812 if (ClearCommError(iCommPort,&err, &stat))
815 return Emulator::LastError();
819 void DCommWins::ResetBuffers(TBool aTx)
821 PurgeComm(iCommPort, PURGE_RXCLEAR | (aTx ? PURGE_TXCLEAR : 0));
825 TBool DCommWins::AreAnyPending()
827 return (iReadPending != 0) || (iWritePending != 0);
831 void DCommWins::WriteCancel()
833 DriverCommand(ETransmitCancel);
837 void DCommWins::ReadCancel()
839 DriverCommand(EReceiveCancel);
842 void DCommWins::SignalChangeCancel()
844 if (iSignalsRequested)
846 iSignalsRequested = 0;
851 void DCommWins::DataAvailableNotificationCancel()
853 if (iDataAvailableNotification)
855 iDataAvailableNotification = EFalse;
856 iLdd->iRxDAError = KErrCancel;
857 iLdd->iRxDataAvailableDfc.Enque();
861 TDes8* DCommWins::RxBuffer()
866 TInt DCommWins::SetRxBufferSize(TInt aSize)
868 aSize += aSize&1; //round up to multiple of 2 bytes as windows complains if odd
869 TInt ret = SetupComm(iCommPort, aSize, KDefaultWinNTWriteBufSize);
872 iRxBufferSize = aSize;
875 dcb.DCBlength = sizeof(dcb);
877 if (!GetCommStateP(iCommPort,&dcb))
878 return Emulator::LastError();
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
885 dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3); //75%
887 if (!SetCommStateP(iCommPort,&dcb))
888 return Emulator::LastError();
892 return Emulator::LastError();
896 TInt DCommWins::RxBufferSize()
898 return iRxBufferSize;
902 TBool DCommWins::IsATerminator(TText8 aChar)
905 for (x=0; x < iConfig->iTerminatorCount; x++)
906 if (aChar == iConfig->iTerminator[x])
912 void DCommWins::ReSizeBuffer(TUint8*& aBuf, TInt& aBufLen, TPtr8& aDes, const TInt aNewLen)
915 if (aNewLen > KSerialBufferMaxSize)
916 Panic(ESerialBufferTooBig);
918 aBufLen = ((aNewLen + KSerialBufferIncrementSize-1) / KSerialBufferIncrementSize) * KSerialBufferIncrementSize;
920 if (aBufLen > KSerialBufferMaxSize)
921 aBufLen = KSerialBufferMaxSize;
923 if (!VirtualAlloc(aBuf, aBufLen, MEM_COMMIT,PAGE_READWRITE))
926 Panic(ESerialBufferTooBig);
928 aDes.Set(aBuf, 0, aBufLen);
932 void DCommWins::Write(DThread* aThread, TAny* aSrc, TInt aLength)
937 RunCommThread(ETransmit0);
941 if (aLength > iOutBufLength)
942 ReSizeBuffer(iOutBufPtr, iOutBufLength, iOutDes, aLength);
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);
952 void DCommWins::NotifySignals(DThread* /*aThread*/, TInt aMask)
954 iSignalsWanted = aMask;
955 RunCommThread(ENotifySignals);
959 void DCommWins::NotifyDataAvailable()
961 RunCommThread(ENotifyDataAvailable);
965 void DCommWins::Read(DThread* /*aThread*/, TAny* /*aDest*/, TInt aLength)
968 TDriverCommand command;
972 iClientReadLength = Abs(aLength);
973 command = EReceiveOneOrMore;
977 iClientReadLength = aLength;
981 if (iClientReadLength > iInBufLength)
982 ReSizeBuffer(iInBufPtr, iInBufLength, iInDes, iClientReadLength);
984 //tell the comms thread to read the data
985 RunCommThread(command);
992 TUint DCommWins::Signals() const
996 GetCommModemStatusP(iCommPort,&signals);
998 if (signals&MS_CTS_ON)
1000 if (signals&MS_DSR_ON)
1002 if (signals&MS_RING_ON)
1004 if (signals&MS_RLSD_ON)
1006 return(status|iSignals);
1010 void DCommWins::SetSignals(TUint aSetMask,TUint aClearMask)
1012 if (aSetMask&KSignalRTS)
1014 iSignals|=KSignalRTS;
1015 EscapeCommFunctionP(iCommPort,SETRTS);
1017 if (aSetMask&KSignalDTR)
1019 iSignals|=KSignalDTR;
1020 EscapeCommFunctionP(iCommPort,SETDTR);
1022 if (aClearMask&KSignalRTS)
1024 iSignals&=(~KSignalRTS);
1025 EscapeCommFunctionP(iCommPort,CLRRTS);
1027 if (aClearMask&KSignalDTR)
1029 iSignals&=(~KSignalDTR);
1030 EscapeCommFunctionP(iCommPort,CLRDTR);
1036 void DCommWins::CheckConfig(TCommConfigV01& /*aConfig*/)
1043 void DCommWins::Configure(TCommConfigV01 &aConfig)
1045 // Ask comm thread to set up the serial port
1052 RunCommThread(EConfigure);
1056 // iCommand=EConfigure;
1061 void DCommWins::DoConfigure()
1063 // Set up the serial port
1069 dcb.DCBlength = sizeof(dcb);
1070 if (!GetCommStateP(iCommPort,&dcb))
1074 //stop if an error happens
1075 dcb.fAbortOnError = TRUE;
1078 switch (iConfig->iRate)
1126 dcb.BaudRate=115200;
1130 switch (iConfig->iParity)
1133 dcb.Parity=NOPARITY;
1134 dcb.fParity = FALSE;
1137 dcb.Parity=EVENPARITY;
1141 dcb.Parity=ODDPARITY;
1145 dcb.Parity = MARKPARITY;
1149 dcb.Parity = SPACEPARITY;
1154 switch (iConfig->iParityError)
1156 case KConfigParityErrorFail:
1157 dcb.fErrorChar = FALSE;
1160 case KConfigParityErrorIgnore:
1161 dcb.fErrorChar = FALSE;
1162 dcb.fAbortOnError = FALSE;
1165 case KConfigParityErrorReplaceChar:
1166 dcb.fErrorChar = TRUE;
1167 dcb.ErrorChar = iConfig->iParityErrorChar;
1172 TUint& hs = iConfig->iHandshake;
1175 //SOFTWARE FLOW CONTROL
1176 dcb.fInX = (hs & KConfigObeyXoff) ? TRUE : FALSE;
1177 dcb.fOutX = (hs & KConfigSendXoff) ? TRUE : FALSE;
1179 dcb.XonChar = iConfig->iXonChar;
1180 dcb.XoffChar = iConfig->iXoffChar;
1181 dcb.ErrorChar = iConfig->iParityErrorChar;
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
1188 dcb.XonLim = (WORD)((iRxBufferSize / 4) * 3); //75%
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;
1199 if (hs & KConfigObeyDCD)
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;
1209 //complete with KErrCommsLineFail if these are set and the line goes low
1211 if (hs & KConfigFailDSR)
1212 iFailSignals |= KSignalDSR;
1214 if (hs & KConfigFailCTS)
1215 iFailSignals |= KSignalCTS;
1217 if (hs & KConfigFailDCD)
1218 iFailSignals |= KSignalDCD;
1221 iTerminatedRead = iConfig->iTerminatorCount > 0;
1223 switch(iConfig->iDataBits)
1239 switch(iConfig->iStopBits)
1242 dcb.StopBits=ONESTOPBIT;
1245 dcb.StopBits=TWOSTOPBITS;
1251 TInt error_r=KErrNone;
1252 if(!SetCommStateP(iCommPort,&dcb))
1253 error_r=GetLastError();
1255 // Clear any error we may have caused
1259 if (ClearCommError(iCommPort,&err,&s)==FALSE)
1264 void DCommWins::Caps(TDes8 &aCaps) const
1266 // Return the current capabilities
1270 GetWinsCommsCaps(aCaps);
1274 void DCommWins::WaitForEvent()
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;
1290 DWORD ret=WaitForMultipleObjectsEx(4,objects,FALSE,INFINITE,TRUE);
1297 if (iDataAvailableNotification)
1299 DataAvailableCompletion(this);
1300 iDataAvailableNotification = EFalse; //stop us repeatedly reporting it
1304 if (iSignalStatus & EV_BREAK)
1306 iBreakDetected=ETrue; // the read will complete with an error
1309 TUint currentSignals = Signals();
1311 //mask out all the signals but the ones we are interested in
1312 iLineFail = (iFailSignals & currentSignals) != iFailSignals;
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
1321 //we have a read to complete
1322 iRXLineFail = ETrue;
1323 PurgeComm(iCommPort, PURGE_RXABORT);
1328 //we have a write to complete
1329 iTXLineFail = ETrue;
1330 PurgeComm(iCommPort, PURGE_TXABORT);
1335 //iSignalsRequested will only have bits set if outstanding request
1336 TUint changed = (currentSignals ^ iSavedSignals) & iSignalsRequested;
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
1345 if (iWritePending == ETransmit0 && (currentSignals & KSignalCTS) != 0)
1346 WriteCompletion(this, KErrNone, 0);
1348 //request another notification event. All events are requested.
1352 DWORD lastError = 0;
1357 ClearCommError(iCommPort,&commErrors,&cstat);
1358 res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
1360 lastError = GetLastError();
1362 while((!res) && (lastError != ERROR_IO_PENDING));
1367 case WAIT_OBJECT_0+1:
1369 // iCommThreadSemaphore has been signalled
1371 DriverCommand(iCommand);
1373 case WAIT_OBJECT_0+2:
1380 TInt error = KErrNone;
1381 if (!GetOverlappedResult(iCommPort, &iWriteOverLapped, &len, FALSE))
1382 error = Emulator::LastError();
1386 ClearCommError(iCommPort,&err,&s);
1388 //if we are failing if one or more of CTS, DSR, DCD go low
1391 error = KErrCommsLineFail;
1392 iTXLineFail = EFalse;
1397 error = KErrCommsFrame;
1398 else if (err & CE_OVERRUN)
1399 error = KErrCommsOverrun;
1400 else if (err & CE_RXPARITY)
1401 error = KErrCommsParity;
1404 WriteCompletion(this, error, len);
1408 case WAIT_OBJECT_0+3:
1414 TInt error = KErrNone;
1415 if (!GetOverlappedResult(iCommPort, &iReadOverLapped, &len, FALSE))
1417 // May have a break already detected to report
1420 error=KErrCommsBreak;
1421 iBreakDetected=EFalse;
1424 error = Emulator::LastError();
1427 iBreakDetected=EFalse; // No error, so any breaks have finished
1431 ClearCommError(iCommPort,&err,&s);
1433 //if we are failing if one or more of CTS, DSR, DCD go low
1436 error = KErrCommsLineFail;
1437 iRXLineFail = EFalse;
1442 error = KErrCommsFrame;
1443 else if (err & CE_OVERRUN)
1444 error = KErrCommsOverrun;
1445 else if (err & CE_RXPARITY)
1446 error = KErrCommsParity;
1449 ReadCompletion(this, error, len);
1453 case WAIT_IO_COMPLETION:
1457 Emulator::LastError();
1463 void DCommWins::DriverCommand(TDriverCommand aCommand)
1465 // Do a driver command - executed when the semaphore has been signalled in the comm port thread
1471 FlushFileBuffers(iCommPort);
1472 SetCommBreak(iCommPort);
1476 ClearCommBreak(iCommPort);
1483 if ((iConfig->iHandshake & KConfigObeyCTS) != 0 && (Signals() & KSignalCTS) == 0)
1484 iWritePending = ETransmit0;
1486 DoWriteComplete(KErrNone);
1495 int r = GetCommTimeouts(iCommPort, &ct);
1496 ct.WriteTotalTimeoutConstant = 0;
1497 ct.WriteTotalTimeoutMultiplier = 0;
1498 r = SetCommTimeouts(iCommPort, &ct);
1500 WriteFileP(iCommPort,iOutDes.Ptr(), iOutDes.Length(), &dummyLen, &iWriteOverLapped);
1501 iWritePending = ETransmit;
1502 iTransmitting= ETrue;
1512 DWORD lastError = 0;
1517 ClearCommError(iCommPort,&commErrors,&cstat);
1518 res = WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
1520 lastError = GetLastError();
1522 while((!res) && (lastError != ERROR_IO_PENDING));
1528 if(iWritePending == ETransmit)
1530 WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
1531 FlushFileBuffers(iCommPort);
1534 iTransmitting=EFalse;
1537 // Cancel any pending writes
1538 if(iWritePending == ETransmit)
1540 PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
1541 WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
1544 iTransmitting=EFalse;
1548 SetCommMaskP(iCommPort,EV_BREAK|EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR);
1549 WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
1554 SignalDriverThread();
1562 case ETransmitCancel:
1563 if (iWritePending == ETransmit)
1564 PurgeComm(iCommPort, PURGE_TXABORT);
1565 // else if (iWritePending == ETransmit0)
1567 // careful - this runs in the context of the kernel thread, not the event thread
1568 iLdd->iTxError = KErrCancel;
1569 iLdd->iTxCompleteDfc.Enque();
1577 int r = GetCommTimeouts(iCommPort, &ct);
1578 ct.ReadIntervalTimeout = 0;
1579 ct.ReadTotalTimeoutMultiplier = 0;
1580 ct.ReadTotalTimeoutConstant = 0;
1581 r = SetCommTimeouts(iCommPort, &ct);
1583 //if we are doing a terminated read.... we need to do it a byte at a time!
1584 if (iTerminatedRead)
1587 ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped);
1591 ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
1594 iReadPending = EReceive;
1598 case EReceiveOneOrMore:
1602 int r = GetCommTimeouts(iCommPort, &ct);
1603 ct.ReadIntervalTimeout = MAXDWORD;
1604 ct.ReadTotalTimeoutMultiplier = MAXDWORD;
1605 ct.ReadTotalTimeoutConstant = KReadOneOrMoreTimeout;
1606 r = SetCommTimeouts(iCommPort, &ct);
1608 //if we are doing a terminated read....
1609 if (iTerminatedRead)
1612 ReadFileP(iCommPort,(void*)iInDes.Ptr(), 1, &dummyLen, &iReadOverLapped);
1616 ReadFileP(iCommPort,(void*)iInDes.Ptr(), iClientReadLength, &dummyLen, &iReadOverLapped);
1619 iReadPending = EReceiveOneOrMore;
1623 case EReceiveCancel:
1625 PurgeComm(iCommPort, PURGE_RXABORT);
1626 else if (iDataAvailableNotification)
1627 DataAvailableNotificationCancel();
1630 case ENotifyDataAvailable:
1632 iDataAvailableNotification = ETrue;
1633 //setup the comms notifications for data available
1637 case ENotifySignals:
1639 TUint currentSignals = Signals();
1640 TUint changed = (currentSignals ^ iSavedSignals) & iSignalsWanted;
1643 SignalCompletion(this, KErrNone, changed, currentSignals);
1644 iSavedSignals = currentSignals;
1648 iSignalsRequested = iSignalsWanted; //checked when signals change
1654 // Panic(EUnknownCommand);
1657 iCommand=EInvalidCommand;
1658 SignalDriverThread();
1662 TDfcQue* DCommWins::DfcQ(TInt /*aUnit*/)
1664 return Kern::DfcQue0();
1668 TInt DCommWins::ValidateConfig(const TCommConfigV01 &aConfig) const
1670 // Check a config structure.
1673 if(aConfig.iRate & EBpsSpecial)
1674 return KErrNotSupported;
1676 switch (aConfig.iParity)
1683 return KErrNotSupported;
1685 switch (aConfig.iRate)
1694 return KErrNotSupported;
1701 inline TBool DCommWins::LineFail()
1708 DECLARE_STANDARD_PDD()
1710 return new DDriverComm;