Update contrib.
1 // Copyright (c) 1997-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 // Implementation of STDLIB serialports.
19 #include <sys/types.h>
20 #include <string.h> // for memcpy
21 #include <sys/errno.h> // for ENOTSOCK
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <sys/serial.h>
28 //define this to allow the code to be built for ER5U without most of the notifications
29 //leave commented for all notifications
30 //#define ER5U_NOTIFICATION_SUPPORT_ONLY
32 _LIT(KCSerialDescPanic, "CSerialDesc");
37 // -----> CSerialTimer (implementation)
40 CSerialTimer::CSerialTimer()
41 : CTimer(CActive::EPriorityHigh)
42 // Construct standard-priority active object
45 CSerialTimer* CSerialTimer::NewLC(CFileDescBase* aFile)
47 CSerialTimer* self=new (ELeave) CSerialTimer;
48 CleanupStack::PushL(self);
49 self->ConstructL(aFile);
53 CSerialTimer* CSerialTimer::NewL(CFileDescBase* aFile)
55 CSerialTimer* self = NewLC(aFile);
60 void CSerialTimer::ConstructL(CFileDescBase* aFile)
62 // Base class second-phase construction.
65 // Add active object to active scheduler
66 CActiveScheduler::Add(this);
70 CSerialTimer::~CSerialTimer()
72 // Make sure we're cancelled
76 void CSerialTimer::DoCancel()
82 void CSerialTimer::IssueRequest()
84 // There should never be an outstanding request at this point.
85 __ASSERT_DEBUG(!IsActive(),User::Panic(KCSerialDescPanic,1));
88 CTimer::After(iFile->TimeoutValue()*1000);
91 void CSerialTimer::RunL()
93 //the timer has gone off.
95 iFile->TimedMessage = NULL;
96 iFile->ReadIsTimed = EFalse;
97 iFile->ReadWasCancelled = ETrue;
104 NONSHARABLE_CLASS(CNotifier) : public CActive
109 void IssueRequest(TInt aRequest, TInt* aRequestParams=NULL);
110 static CNotifier* NewLC(CSerialDesc* aPort);
111 static CNotifier* NewL(CSerialDesc* aPort);
112 void Construct(CSerialDesc* aPort);
113 void Complete(TInt aVal);
116 enum RequestTypes {None, DataAvailable, OutputEmpty, Break, Signals, WriteErrors};
119 CSerialDesc * iSerialPort;
120 enum RequestTypes iRequest;
122 TInt* iRequestParams;
126 CNotifier::CNotifier() : CActive(CActive::EPriorityStandard), iRequest(None), iRequestData(0), iRequestParams(NULL)
131 void CNotifier::IssueRequest(TInt aRequest, TInt* aRequestParams)
133 iRequestParams = aRequestParams;
135 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
136 if (KNotifyDataAvailable == aRequest)
138 iRequest = DataAvailable;
139 iSerialPort->NotifyDataAvailable(iStatus);
142 else if (KNotifyOutputEmpty == aRequest)
144 iRequest = OutputEmpty;
145 iSerialPort->NotifyOutputEmpty(iStatus);
148 else if (KNotifyBreakInt == aRequest)
151 iSerialPort->NotifyBreak(iStatus);
154 else if (aRequest & (KNotifyCD|KNotifyCTS|KNotifyDSR|KNotifyRI)) //signals
156 TUint signalsRequested = 0;
158 //build up the mask of signals to request
159 if (aRequest & KNotifyCD) signalsRequested |= KSignalDCD;
160 if (aRequest & KNotifyCTS) signalsRequested |= KSignalCTS;
161 if (aRequest & KNotifyDSR) signalsRequested |= KSignalDSR;
162 if (aRequest & KNotifyRI) signalsRequested |= KSignalRNG;
164 iSerialPort->NotifySignalChange(iStatus, iRequestData, signalsRequested);
168 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
169 if (aRequest & (KNotifyFramingError|KNotifyOverrunError|KNotifyParityError))
171 iRequest = WriteErrors;
172 iSerialPort->NotifyWriteErrors(iStatus, &iRequestData, aRequest);
178 void CNotifier::RunL()
181 //cancel all the others
182 //use iRequest to determine what we are doing here
184 CNotifier** ppn = NULL;
187 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
190 iSerialPort->iNotifyParamPtr[0] = KNotifyDataAvailable;
191 ppn = &iSerialPort->iDataAvailableNotifier;
195 iSerialPort->iNotifyParamPtr[0] = KNotifyOutputEmpty;
196 ppn = &iSerialPort->iOutputEmptyNotifier;
200 iSerialPort->iNotifyParamPtr[0] = KNotifyBreakInt;
201 ppn = &iSerialPort->iBreakNotifier;
206 ppn = &iSerialPort->iSignalsNotifier;
207 iSerialPort->iNotifyParamPtr[0] = 0;
208 iSerialPort->iNotifyParamPtr[1] = 0;
209 if (iRequestData & KDCDChanged)
211 iSerialPort->iNotifyParamPtr[0] |= KNotifyCD;
212 iSerialPort->iNotifyParamPtr[1] |= (iRequestData & KSignalDCD);
215 if (iRequestData & KCTSChanged)
217 iSerialPort->iNotifyParamPtr[0] |= KNotifyCTS;
218 iSerialPort->iNotifyParamPtr[1] |= (iRequestData & KSignalCTS);
221 if (iRequestData & KDSRChanged)
223 iSerialPort->iNotifyParamPtr[0] |= KNotifyDSR;
224 iSerialPort->iNotifyParamPtr[1] |= (iRequestData & KSignalDSR);
227 if (iRequestData & KRNGChanged)
229 iSerialPort->iNotifyParamPtr[0] |= KNotifyRI;
230 iSerialPort->iNotifyParamPtr[1] |= (iRequestData & KSignalRNG);
235 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
238 iSerialPort->iNotifyParamPtr[0] = iRequestData;
239 iSerialPort->iNotifyParamPtr[1] = 0;
240 ppn = &iSerialPort->iErrorsNotifier;
245 __ASSERT_DEBUG(EFalse, User::Panic(KCSerialDescPanic, 1));
249 //cancel all the others
250 iSerialPort->CancelNotifiers(this); //telling it who we are.
252 //and complete the outstanding user request
253 User::RequestComplete(iSerialPort->iNotifyStatus, iStatus.Int());
255 if (ppn) *ppn = NULL;
258 void CNotifier::DoCancel()
262 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
265 iSerialPort->NotifyDataAvailableCancel();
269 iSerialPort->NotifyOutputEmptyCancel();
273 iSerialPort->NotifyBreakCancel();
277 iSerialPort->NotifySignalChangeCancel();
279 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
281 iSerialPort->NotifyWriteErrorsCancel();
292 void CNotifier::Complete(TInt aVal)
294 TRequestStatus* ps = &iStatus;
295 User::RequestComplete(ps, aVal);
299 CNotifier* CNotifier::NewLC(CSerialDesc* aPort)
301 CNotifier* self=new (ELeave) CNotifier;
302 CleanupStack::PushL(self);
303 self->Construct(aPort);
307 CNotifier* CNotifier::NewL(CSerialDesc* aPort)
309 CNotifier* self = NewLC(aPort);
314 void CNotifier::Construct(CSerialDesc* aPort)
317 CActiveScheduler::Add(this) ; // add to active scheduler
320 CNotifier::~CNotifier()
330 // The Serial descriptor class
332 TInt CSerialDesc::Open(RCommServ& aSession, const wchar_t* name, int mode, int /*perms*/)
334 //the name will be a wide version of COM?: or IRCOM?: where ? is a number 1 to 9.
335 //this has already been checked in the call to CFileDescBase open.
339 TInt err = KErrArgument;
343 //load the comms module we require
344 err = aSession.LoadCommModule(_L("ECUART"));
345 if (KErrAlreadyExists != err && KErrNone != err) //problem
347 //convert the name into an epoc port name
349 TBuf<7> epocName(_L("COMM::0"));
350 epocName[6] = (TText)(name[3] - 1);
352 //try opening as a dte or a dce
353 err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDTE);
355 err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDCE);
360 err = aSession.LoadCommModule(_L("IrCOMM"));
361 if (KErrAlreadyExists != err && KErrNone != err) //problem
363 //convert the name into an epoc port name
365 TBuf<9> epocName(_L("IrCOMM::0"));
366 epocName[8] = (TText)(name[5] - 1);
368 //try opening as a dte or a dce
369 err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDTE);
371 err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDCE);
376 void CSerialDesc::UserClose()
381 TInt CSerialDesc::FinalClose()
390 TBool CSerialDesc::TimedRead()
392 //if we have a timeout without a threshold we need an external timer
393 return (-1 != iReadTimeout && -1 == iReadThreshold);
397 void CSerialDesc::Read(TDes8& aBuf, TRequestStatus& aStatus)
401 if (-1 == iReadThreshold)
403 iCommPort.ReadOneOrMore(aStatus, aBuf);
407 TInt len = (iReadThreshold < aBuf.MaxLength() ? iReadThreshold : aBuf.MaxLength());
408 if (-1 == iReadTimeout)
410 //read threshold with no timeout
411 iCommPort.Read(aStatus, aBuf, len);
415 //read threshold and timeout
416 TTimeIntervalMicroSeconds32 timeout(iReadTimeout*1000);
417 iCommPort.Read(aStatus, timeout, aBuf, len);
424 void CSerialDesc::Write (TDes8& aBuf, TRequestStatus& aStatus)
426 iCommPort.Write(aStatus, aBuf);
430 void CSerialDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
436 aCmd &= ~0x4000; //mask off the queue bit!
440 case COMMIOCTL_SETSIGNALS:
442 int* param =REINTERPRET_CAST(int*,aParam);
443 TUint setMask = (TUint)param[0];
444 TUint clearMask = (TUint)param[1];
445 iCommPort.SetSignals(setMask, clearMask);
449 case COMMIOCTL_GETSIGNALS:
451 int* param =REINTERPRET_CAST(int*,aParam);
452 TUint signals = iCommPort.Signals();
453 *param = (int)signals;
457 case COMMIOCTL_SETCONFIG:
459 SerialConfig * param =REINTERPRET_CAST(SerialConfig *,aParam);
462 TCommConfigV01& cfg01 =cfg();
464 cfg01.iRate = (enum TBps)param->iRate;
465 cfg01.iDataBits = (enum TDataBits)param->iDataBits;
466 cfg01.iStopBits = (enum TStopBits)param->iStopBits;
467 cfg01.iParity = (enum TParity)param->iParity;
468 cfg01.iHandshake = param->iHandshake;
469 cfg01.iParityError = param->iParityError;
470 cfg01.iFifo = param->iFifo;
471 cfg01.iSpecialRate = param->iSpecialRate;
472 cfg01.iTerminatorCount = param->iTerminatorCount;
473 cfg01.iXonChar = param->iXonChar;
474 cfg01.iXoffChar = param->iXoffChar;
475 cfg01.iParityErrorChar = param->iParityErrorChar;
476 cfg01.iSIREnable = (enum TSir)param->iSIREnable;
477 cfg01.iSIRSettings = param->iSIRSettings;
479 for (int i =0; i < ConfigMaxTerminators; i++)
480 cfg01.iTerminator[i] = param->iTerminator[i];
482 iCommPort.SetConfig(cfg);
486 case COMMIOCTL_GETCONFIG:
488 SerialConfig * param =REINTERPRET_CAST(SerialConfig *,aParam);
490 iCommPort.Config(cfg);
491 TCommConfigV01& cfg01 =cfg();
493 param->iRate = (enum Bps)cfg01.iRate;
494 param->iDataBits = (enum DataBits)cfg01.iDataBits;
495 param->iStopBits = (enum StopBits)cfg01.iStopBits;
496 param->iParity = (enum Parity)cfg01.iParity;
497 param->iHandshake = cfg01.iHandshake;
498 param->iParityError = cfg01.iParityError;
499 param->iFifo = cfg01.iFifo;
500 param->iSpecialRate = cfg01.iSpecialRate;
501 param->iTerminatorCount = cfg01.iTerminatorCount;
502 for (int i =0; i < ConfigMaxTerminators; i++)
503 param->iTerminator[i] = cfg01.iTerminator[i];
504 param->iXonChar = cfg01.iXonChar;
505 param->iXoffChar = cfg01.iXoffChar;
506 param->iParityErrorChar = cfg01.iParityErrorChar;
507 param->iSIREnable = (enum Sir)cfg01.iSIREnable;
508 param->iSIRSettings = cfg01.iSIRSettings;
512 case COMMIOCTL_BREAK:
514 int* param =REINTERPRET_CAST(int*,aParam);
515 TTimeIntervalMicroSeconds32 time(*param);
516 iCommPort.Break(aStatus, time);
520 case COMMIOCTL_SETREADTIMEOUT:
522 int* param =REINTERPRET_CAST(int*,aParam);
523 iReadTimeout = *param;
527 case COMMIOCTL_GETREADTIMEOUT:
529 int* param =REINTERPRET_CAST(int*,aParam);
530 *param = iReadTimeout;
534 case COMMIOCTL_SETREADTHRESHOLD:
536 int* param =REINTERPRET_CAST(int*,aParam);
537 iReadThreshold = *param;
541 case COMMIOCTL_GETREADTHRESHOLD:
543 int* param =REINTERPRET_CAST(int*,aParam);
544 *param = iReadThreshold;
548 case COMMIOCTL_SETBUFFERLENGTH:
550 int* param =REINTERPRET_CAST(int*,aParam);
551 iCommPort.SetReceiveBufferLength(TInt(*param));
555 case COMMIOCTL_GETBUFFERLENGTH:
557 int* param =REINTERPRET_CAST(int*,aParam);
558 *param = iCommPort.ReceiveBufferLength();
562 case COMMIOCTL_NOTIFYSUPPORTED:
564 int* param =REINTERPRET_CAST(int*,aParam);
565 *param = NotifiesSupported();
569 case REAL_COMMIOCTL_NOTIFY:
571 int* param =REINTERPRET_CAST(int*,aParam);
572 //if they are supported
573 if (RequestedNotifiesSupported(*param))
575 //see if we need real notifications or we are to fake them
576 //always use aStatus for the final thing
577 TBool wantDataAvailable = *param & KNotifyDataAvailable;
578 TBool wantOutputEmpty = *param & KNotifyOutputEmpty;
579 TBool wantBreakInt = *param & KNotifyBreakInt;
580 TBool wantSignals = *param & (KNotifyCD|KNotifyCTS|KNotifyDSR|KNotifyRI);
581 TBool wantErrors = *param & (KNotifyFramingError|KNotifyOverrunError|KNotifyParityError);
583 iDataAvailableNotifier = NULL;
584 iOutputEmptyNotifier = NULL;
585 iBreakNotifier = NULL;
586 iSignalsNotifier = NULL;
587 iErrorsNotifier = NULL;
591 if (wantDataAvailable) iDataAvailableNotifier = CNotifier::NewL(this);
592 if (wantOutputEmpty) iOutputEmptyNotifier = CNotifier::NewL(this);
593 if (wantBreakInt) iBreakNotifier = CNotifier::NewL(this);
594 if (wantSignals) iSignalsNotifier = CNotifier::NewL(this);
595 if (wantErrors) iErrorsNotifier = CNotifier::NewL(this);
598 if (KErrNone == tRes)
600 //smashing, no failure, request those events
601 if (wantDataAvailable) iDataAvailableNotifier->IssueRequest(KNotifyDataAvailable);
602 if (wantOutputEmpty) iOutputEmptyNotifier->IssueRequest(KNotifyOutputEmpty);
603 if (wantBreakInt) iBreakNotifier->IssueRequest(KNotifyBreakInt);
604 if (wantSignals) iSignalsNotifier->IssueRequest(*param & (KNotifyCD|KNotifyCTS|KNotifyDSR|KNotifyRI));
605 if (wantErrors) iErrorsNotifier->IssueRequest(*param & (KNotifyFramingError|KNotifyOverrunError|KNotifyParityError));
607 iRequestedSignals = *param;
608 iNotifyParamPtr = REINTERPRET_CAST(unsigned int*,aParam);
609 iNotifyStatus = &aStatus;
610 aStatus = KRequestPending;
611 return; //on an async call here
615 //deal with the problem
616 //we're going to have to tidy up, delete things etc
617 delete iDataAvailableNotifier;
618 delete iOutputEmptyNotifier;
619 delete iBreakNotifier;
620 delete iSignalsNotifier;
621 delete iErrorsNotifier;
622 iDataAvailableNotifier = NULL;
623 iOutputEmptyNotifier = NULL;
624 iBreakNotifier = NULL;
625 iSignalsNotifier = NULL;
626 iErrorsNotifier = NULL;
633 ret = KErrNotSupported;
634 *param &=~NotifiesSupported();
641 ret=KErrNotSupported;
648 Complete(aStatus,ret);
652 TInt CSerialDesc::IoctlCompletion(int /*aCmd*/, void* /*aParam*/, TInt aStatus)
658 void CSerialDesc::ReadCancel()
660 iCommPort.ReadCancel();
664 void CSerialDesc::IoctlCancel()
666 //stop the ioctl if in progress
667 CancelNotifiers(NULL);
671 iNotifyParamPtr[0] = 0;
672 Complete(*iNotifyStatus, -3);
677 TInt CSerialDesc::ReadCompletion (TDes8& /*aBuf*/, TInt aStatus)
679 //The read has completed.
680 //See if we need to signal 'cos it completed with an error and someone is waiting
681 //on a notification. In which case we need to complete the request with the correct results.
683 if ((aStatus < 0) && (iRequestedSignals&(KNotifyFramingError|KNotifyOverrunError|KNotifyParityError))) //we have a signal outstanding we can deal with here
687 case KErrCommsFrame: //comms framing error
688 if (iRequestedSignals&KNotifyFramingError)
689 Notify(KNotifyFramingError);
692 case KErrCommsOverrun: //comms overrrun error
693 if (iRequestedSignals&KNotifyOverrunError)
694 Notify(KNotifyOverrunError);
697 case KErrCommsParity: //comms parity error
698 if (iRequestedSignals&KNotifyParityError)
699 Notify(KNotifyParityError);
703 //an error we don't signal
712 TBool CSerialDesc::RequestedNotifiesSupported(TInt aRequested)
714 //return true if these notifies are OK. 0 if any of them are illegal
716 TInt mask = ~(NotifiesSupported());
717 return !(aRequested&mask);
720 TInt CSerialDesc::NotifiesSupported()
722 //return which notifies are supported.
723 //looks like the driver/server is going to have to be interrogated here
725 //start with the ones we can fake
726 TInt supported = KNotifyFramingError|KNotifyOverrunError|KNotifyParityError;
728 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
729 //get the supported ones from C32
731 TCommCapsV02& deviceCapabilities = devCap();
732 deviceCapabilities.iNotificationCaps = 0;
733 iCommPort.Caps(devCap);
737 if (deviceCapabilities.iNotificationCaps & KNotifySignalsChangeSupported)
738 supported |= (KNotifyCD|KNotifyCTS|KNotifyDSR|KNotifyRI);
741 if (deviceCapabilities.iNotificationCaps & KNotifyBreakSupported)
742 supported |= KNotifyBreakInt;
746 if (deviceCapabilities.iNotificationCaps & KNotifyDataAvailableSupported)
747 supported |= KNotifyDataAvailable;
750 if (deviceCapabilities.iNotificationCaps & KNotifyOutputEmptySupported)
751 supported |= KNotifyOutputEmpty;
753 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
758 void CSerialDesc::Notify(TInt aVal)
762 // iNotifyParamPtr[0] = aVal;
763 *iRequestDataPtr = aVal;
764 iErrorsNotifier->Complete(0);
769 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
770 void CSerialDesc::NotifyDataAvailable(TRequestStatus& aStatus)
772 iCommPort.NotifyDataAvailable(aStatus);
775 void CSerialDesc::NotifyDataAvailableCancel()
777 iCommPort.NotifyDataAvailableCancel();
780 void CSerialDesc::NotifyOutputEmpty(TRequestStatus& aStatus)
782 iCommPort.NotifyOutputEmpty(aStatus);
785 void CSerialDesc::NotifyOutputEmptyCancel()
787 iCommPort.NotifyOutputEmptyCancel();
790 void CSerialDesc::NotifyBreak(TRequestStatus& aStatus)
792 iCommPort.NotifyBreak(aStatus);
795 void CSerialDesc::NotifyBreakCancel()
797 iCommPort.NotifyBreakCancel();
800 void CSerialDesc::NotifySignalChange(TRequestStatus& aStatus, TUint& aRequestData, TUint aSignalsMask)
802 iCommPort.NotifySignalChange(aStatus, aRequestData, aSignalsMask);
805 void CSerialDesc::NotifySignalChangeCancel()
807 iCommPort.NotifySignalChangeCancel();
809 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
811 void CSerialDesc::NotifyWriteErrors(TRequestStatus& aStatus, TUint* aRequestData, TUint aSignalsMask)
813 iRequestedSignals = aSignalsMask;
814 iRequestDataPtr = aRequestData;
815 // iNotifyParamPtr = aRequestData;
816 aStatus = KRequestPending;
819 void CSerialDesc::NotifyWriteErrorsCancel()
821 iErrorsNotifier->Complete(KErrCancel);
824 TUint CSerialDesc::Signals()
826 return iCommPort.Signals();
830 void CSerialDesc::CancelNotifiers(const CNotifier* aCompletedNotifier)
832 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
833 if (iDataAvailableNotifier && (aCompletedNotifier != iDataAvailableNotifier))
835 iDataAvailableNotifier->Cancel();
836 delete iDataAvailableNotifier;
837 iDataAvailableNotifier = NULL;
840 if (iOutputEmptyNotifier && (aCompletedNotifier != iOutputEmptyNotifier))
842 iOutputEmptyNotifier->Cancel();
843 delete iOutputEmptyNotifier;
844 iOutputEmptyNotifier = NULL;
847 if (iBreakNotifier && (aCompletedNotifier != iBreakNotifier))
849 iBreakNotifier->Cancel();
850 delete iBreakNotifier;
851 iBreakNotifier = NULL;
855 if (iSignalsNotifier && (aCompletedNotifier != iSignalsNotifier))
857 iSignalsNotifier->Cancel();
858 delete iSignalsNotifier;
859 iSignalsNotifier = NULL;
861 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
862 if (iErrorsNotifier && (aCompletedNotifier != iErrorsNotifier))
864 iErrorsNotifier->Cancel();
865 delete iErrorsNotifier;
866 iErrorsNotifier = NULL;