os/ossrv/genericopenlibs/cstdlib/USTLIB/USERIAL.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // Implementation of STDLIB serialports.
    15 // 
    16 //
    17 
    18 #include "FDESC.H"
    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>
    25 #include <c32comm.h>
    26 
    27 
    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
    31 #ifdef _DEBUG
    32 _LIT(KCSerialDescPanic, "CSerialDesc");
    33 #endif
    34 
    35 //
    36 //
    37 // -----> CSerialTimer (implementation)
    38 //
    39 //
    40 CSerialTimer::CSerialTimer()
    41 	: CTimer(CActive::EPriorityHigh)
    42 	  // Construct standard-priority active object
    43 	{};
    44 
    45 CSerialTimer* CSerialTimer::NewLC(CFileDescBase* aFile)
    46 	{
    47 	CSerialTimer* self=new (ELeave) CSerialTimer;
    48 	CleanupStack::PushL(self);
    49 	self->ConstructL(aFile);
    50 	return self;
    51 	}
    52 
    53 CSerialTimer* CSerialTimer::NewL(CFileDescBase* aFile)
    54 	{
    55 	CSerialTimer* self = NewLC(aFile);
    56 	CleanupStack::Pop();
    57 	return self;
    58 	}
    59 
    60 void CSerialTimer::ConstructL(CFileDescBase* aFile)
    61 	{
    62 	  // Base class second-phase construction.
    63 	CTimer::ConstructL();
    64 	iFile = aFile;
    65 	  // Add active object to active scheduler
    66 	CActiveScheduler::Add(this); 
    67 	}
    68 
    69 
    70 CSerialTimer::~CSerialTimer()
    71 	{
    72 	  // Make sure we're cancelled
    73 	Cancel();
    74 	}
    75 
    76 void CSerialTimer::DoCancel()
    77 	{
    78 	  // Base class
    79 	CTimer::DoCancel(); 
    80 	}
    81 
    82 void CSerialTimer::IssueRequest()
    83 	{
    84 	  // There should never be an outstanding request at this point.
    85 	__ASSERT_DEBUG(!IsActive(),User::Panic(KCSerialDescPanic,1));
    86 
    87 	  // Request
    88 	CTimer::After(iFile->TimeoutValue()*1000);
    89 	}
    90 
    91 void CSerialTimer::RunL()
    92 	{
    93 		//the timer has gone off.
    94 	iFile->ReadCancel();
    95 	iFile->TimedMessage = NULL;
    96 	iFile->ReadIsTimed = EFalse;
    97 	iFile->ReadWasCancelled = ETrue;
    98 	delete this;
    99 	}
   100 
   101 
   102 
   103 /****/
   104 NONSHARABLE_CLASS(CNotifier) : public CActive
   105 	{
   106 	public:
   107 		CNotifier();
   108 		~CNotifier();
   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);
   114 
   115 	private:
   116 		enum RequestTypes {None, DataAvailable, OutputEmpty, Break, Signals, WriteErrors};
   117 		void DoCancel();
   118 		void RunL();
   119 		CSerialDesc * iSerialPort;
   120 		enum RequestTypes iRequest;
   121 		TUint iRequestData;
   122 		TInt* iRequestParams;
   123 
   124 } ;
   125 
   126 CNotifier::CNotifier() : CActive(CActive::EPriorityStandard), iRequest(None), iRequestData(0), iRequestParams(NULL)
   127 	{
   128 	}
   129 
   130 
   131 void CNotifier::IssueRequest(TInt aRequest, TInt* aRequestParams)
   132 	{
   133 	iRequestParams = aRequestParams;
   134 	
   135 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
   136 	if (KNotifyDataAvailable == aRequest)
   137 		{
   138 		iRequest = DataAvailable;
   139 		iSerialPort->NotifyDataAvailable(iStatus);
   140 		}
   141 
   142 	else if (KNotifyOutputEmpty == aRequest)
   143 		{
   144 		iRequest = OutputEmpty;
   145 		iSerialPort->NotifyOutputEmpty(iStatus);
   146 		}
   147 	
   148 	else if (KNotifyBreakInt == aRequest)
   149 		{
   150 		iRequest = Break;
   151 		iSerialPort->NotifyBreak(iStatus);
   152 		}
   153 	
   154 	else if (aRequest & (KNotifyCD|KNotifyCTS|KNotifyDSR|KNotifyRI))	//signals
   155 		{
   156 		TUint signalsRequested = 0;
   157 
   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;
   163 		iRequest = Signals;
   164 		iSerialPort->NotifySignalChange(iStatus, iRequestData, signalsRequested);
   165 		}
   166 	
   167 	else 
   168 #endif	//ER5U_NOTIFICATION_SUPPORT_ONLY
   169 		if (aRequest & (KNotifyFramingError|KNotifyOverrunError|KNotifyParityError))
   170 		{
   171 		iRequest = WriteErrors;
   172 		iSerialPort->NotifyWriteErrors(iStatus, &iRequestData, aRequest);
   173 		}
   174 		
   175 	SetActive();
   176 	}
   177 
   178 void CNotifier::RunL()
   179 	{
   180 	//now what!
   181 	//cancel all the others
   182 	//use iRequest to determine what we are doing here
   183 
   184 	CNotifier** ppn = NULL;
   185 	switch (iRequest)
   186 		{
   187 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
   188 
   189 		case DataAvailable:
   190 			iSerialPort->iNotifyParamPtr[0] = KNotifyDataAvailable;
   191 			ppn = &iSerialPort->iDataAvailableNotifier;
   192 			break;
   193 
   194 		case OutputEmpty:
   195 			iSerialPort->iNotifyParamPtr[0] = KNotifyOutputEmpty;
   196 			ppn = &iSerialPort->iOutputEmptyNotifier;
   197 			break;
   198 
   199 		case Break:
   200 			iSerialPort->iNotifyParamPtr[0] = KNotifyBreakInt;
   201 			ppn = &iSerialPort->iBreakNotifier;
   202 			break;
   203 
   204 		case Signals:
   205 			{
   206 			ppn = &iSerialPort->iSignalsNotifier;
   207 			iSerialPort->iNotifyParamPtr[0] = 0;
   208 			iSerialPort->iNotifyParamPtr[1] = 0;
   209 			if (iRequestData & KDCDChanged)
   210 				{
   211 				iSerialPort->iNotifyParamPtr[0] |=  KNotifyCD;
   212 				iSerialPort->iNotifyParamPtr[1] |=  (iRequestData & KSignalDCD);
   213 				}
   214 
   215 			if (iRequestData & KCTSChanged)
   216 				{
   217 				iSerialPort->iNotifyParamPtr[0] |=  KNotifyCTS;
   218 				iSerialPort->iNotifyParamPtr[1] |=  (iRequestData & KSignalCTS);
   219 				}
   220 
   221 			if (iRequestData & KDSRChanged)
   222 				{
   223 				iSerialPort->iNotifyParamPtr[0] |=  KNotifyDSR;
   224 				iSerialPort->iNotifyParamPtr[1] |=  (iRequestData & KSignalDSR);
   225 				}
   226 
   227 			if (iRequestData & KRNGChanged)
   228 				{
   229 				iSerialPort->iNotifyParamPtr[0] |=  KNotifyRI;
   230 				iSerialPort->iNotifyParamPtr[1] |=  (iRequestData & KSignalRNG);
   231 				}
   232 
   233 			}
   234 			break;
   235 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
   236 		case WriteErrors:
   237 			{
   238 			iSerialPort->iNotifyParamPtr[0] = iRequestData;
   239 			iSerialPort->iNotifyParamPtr[1] = 0;
   240 			ppn = &iSerialPort->iErrorsNotifier;
   241 			}
   242 			break;
   243 
   244 		default:
   245 			__ASSERT_DEBUG(EFalse, User::Panic(KCSerialDescPanic, 1));
   246 			break;
   247 		}
   248 
   249 	//cancel all the others
   250 	iSerialPort->CancelNotifiers(this);	//telling it who we are.
   251 
   252 	//and complete the outstanding user request
   253 	User::RequestComplete(iSerialPort->iNotifyStatus, iStatus.Int());
   254 	delete this;
   255 	if (ppn) *ppn = NULL;
   256 	}
   257 
   258 void CNotifier::DoCancel()
   259 	{
   260 	switch (iRequest)
   261 		{
   262 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
   263 
   264 		case DataAvailable:
   265 			iSerialPort->NotifyDataAvailableCancel();
   266 			break;
   267 
   268 		case OutputEmpty:
   269 			iSerialPort->NotifyOutputEmptyCancel();
   270 			break;
   271 
   272 		case Break:
   273 			iSerialPort->NotifyBreakCancel();
   274 			break;
   275 
   276 		case Signals:
   277 			iSerialPort->NotifySignalChangeCancel();
   278 			break;
   279 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
   280 		case WriteErrors:
   281 			iSerialPort->NotifyWriteErrorsCancel();
   282 			break;
   283 
   284 		default:
   285 			break;
   286 		}
   287 
   288 
   289 	}
   290 
   291 
   292 void CNotifier::Complete(TInt aVal)
   293 	{
   294 	TRequestStatus* ps = &iStatus;
   295 	User::RequestComplete(ps, aVal);
   296 	}
   297 
   298 
   299 CNotifier* CNotifier::NewLC(CSerialDesc* aPort)
   300 	{
   301 	CNotifier* self=new (ELeave) CNotifier;
   302 	CleanupStack::PushL(self);
   303 	self->Construct(aPort);
   304 	return self;
   305 	}
   306 
   307 CNotifier* CNotifier::NewL(CSerialDesc* aPort)
   308 	{
   309 	CNotifier* self = NewLC(aPort);
   310 	CleanupStack::Pop();
   311 	return self;
   312 	}
   313 
   314 void CNotifier::Construct(CSerialDesc* aPort)
   315 	{
   316 	iSerialPort = aPort;
   317 	CActiveScheduler::Add(this) ;  // add to active scheduler
   318 	}
   319 
   320 CNotifier::~CNotifier()
   321 	{
   322 	Cancel();
   323 	}
   324 
   325 
   326 /****/
   327 
   328 
   329 
   330 // The Serial descriptor class
   331 
   332 TInt CSerialDesc::Open(RCommServ& aSession, const wchar_t* name, int mode, int /*perms*/)
   333 	{
   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.
   336 
   337 	
   338 	
   339 	TInt err = KErrArgument;
   340 	if (L'C' == name[0])
   341 		{
   342 		//serial port
   343 		//load the comms module we require
   344 		err = aSession.LoadCommModule(_L("ECUART"));
   345 		if (KErrAlreadyExists != err && KErrNone != err)	//problem
   346 			return err;
   347 		//convert the name into an epoc port name
   348 		//eg COMM::0
   349 		TBuf<7> epocName(_L("COMM::0"));
   350 		epocName[6] = (TText)(name[3] - 1);
   351 
   352 		//try opening as a dte or a dce
   353 		err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDTE);
   354 		if (err) 			
   355 			err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDCE);
   356 		}
   357 	else
   358 		{
   359 		//IR port
   360 		err = aSession.LoadCommModule(_L("IrCOMM"));
   361 		if (KErrAlreadyExists != err && KErrNone != err)	//problem
   362 			return err;
   363 		//convert the name into an epoc port name
   364 		//eg COMM::0
   365 		TBuf<9> epocName(_L("IrCOMM::0"));
   366 		epocName[8] = (TText)(name[5] - 1);
   367 
   368 		//try opening as a dte or a dce
   369 		err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDTE);
   370 		if (err) 			
   371 			err = iCommPort.Open(aSession, epocName, (enum TCommAccess)mode, ECommRoleDCE);
   372 		}
   373 	return err;
   374 	}
   375 
   376 void CSerialDesc::UserClose()
   377 	{
   378 	IoctlCancel();
   379 	}
   380 
   381 TInt CSerialDesc::FinalClose()
   382 	{
   383 	iCommPort.Close();
   384 	return 0;
   385 	}
   386 
   387 
   388 
   389 
   390 TBool CSerialDesc::TimedRead()
   391 	{
   392 		//if we have a timeout without a threshold we need an external timer
   393 		return (-1 != iReadTimeout && -1 == iReadThreshold);
   394 	}
   395 
   396 
   397 void CSerialDesc::Read(TDes8& aBuf, TRequestStatus& aStatus)
   398 	{
   399 	//do a read..
   400 	//4 different ones
   401 	if (-1 == iReadThreshold)
   402 		{
   403 		iCommPort.ReadOneOrMore(aStatus, aBuf);
   404 		}
   405 	else
   406 		{
   407 		TInt len = (iReadThreshold < aBuf.MaxLength() ? iReadThreshold : aBuf.MaxLength());
   408 		if (-1 == iReadTimeout)
   409 			{
   410 			//read threshold with no timeout
   411 			iCommPort.Read(aStatus, aBuf, len);
   412 			}
   413 		else
   414 			{
   415 			//read threshold and timeout
   416 			TTimeIntervalMicroSeconds32 timeout(iReadTimeout*1000);
   417 			iCommPort.Read(aStatus, timeout, aBuf, len);
   418 			}
   419 		}
   420 
   421 	}
   422 
   423 
   424 void CSerialDesc::Write (TDes8& aBuf, TRequestStatus& aStatus)
   425 	{
   426 	iCommPort.Write(aStatus, aBuf);
   427 	}
   428 
   429 
   430 void CSerialDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
   431 	{
   432 	TInt ret=KErrNone;
   433 	if (aParam)
   434 		{
   435 		
   436 		aCmd &= ~0x4000;	//mask off the queue bit!
   437 
   438 		switch (aCmd)
   439 			{
   440 			case COMMIOCTL_SETSIGNALS:
   441 				{
   442 				int* param =REINTERPRET_CAST(int*,aParam);
   443 				TUint setMask = (TUint)param[0];
   444 				TUint clearMask = (TUint)param[1];
   445 				iCommPort.SetSignals(setMask, clearMask);
   446 				}
   447 				break;
   448 
   449 			case COMMIOCTL_GETSIGNALS:
   450 				{
   451 				int* param =REINTERPRET_CAST(int*,aParam);
   452 				TUint signals = iCommPort.Signals();
   453 				*param = (int)signals;
   454 				}
   455 				break;
   456 
   457 			case COMMIOCTL_SETCONFIG:	
   458 				{
   459 				SerialConfig * param =REINTERPRET_CAST(SerialConfig *,aParam);
   460 				TCommConfig cfg;
   461 
   462 				TCommConfigV01& cfg01 =cfg();
   463 				
   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;
   478 
   479 				for (int i =0; i < ConfigMaxTerminators; i++)
   480 					cfg01.iTerminator[i] = param->iTerminator[i];
   481 
   482 				iCommPort.SetConfig(cfg);
   483 				}
   484 				break;
   485 
   486 			case COMMIOCTL_GETCONFIG:	
   487 				{
   488 				SerialConfig * param =REINTERPRET_CAST(SerialConfig *,aParam);
   489 				TCommConfig cfg;
   490 				iCommPort.Config(cfg);
   491 				TCommConfigV01& cfg01 =cfg();
   492 				
   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;
   509 				}
   510 				break;
   511 
   512 			case COMMIOCTL_BREAK:	
   513 				{
   514 				int* param =REINTERPRET_CAST(int*,aParam);
   515 				TTimeIntervalMicroSeconds32 time(*param);
   516 				iCommPort.Break(aStatus, time);
   517 				return;
   518 				}
   519 
   520 			case COMMIOCTL_SETREADTIMEOUT:
   521 				{
   522 				int* param =REINTERPRET_CAST(int*,aParam);
   523 				iReadTimeout = *param;
   524 				}
   525 				break;
   526 
   527 			case COMMIOCTL_GETREADTIMEOUT:
   528 				{
   529 				int* param =REINTERPRET_CAST(int*,aParam);
   530 				*param = iReadTimeout;
   531 				}
   532 				break;
   533 
   534 			case COMMIOCTL_SETREADTHRESHOLD:
   535 				{
   536 				int* param =REINTERPRET_CAST(int*,aParam);
   537 				iReadThreshold = *param;
   538 				}
   539 				break;
   540 
   541 			case COMMIOCTL_GETREADTHRESHOLD:
   542 				{
   543 				int* param =REINTERPRET_CAST(int*,aParam);
   544 				*param = iReadThreshold;
   545 				}
   546 				break;
   547 
   548 			case COMMIOCTL_SETBUFFERLENGTH:
   549 				{
   550 				int* param =REINTERPRET_CAST(int*,aParam);
   551 				iCommPort.SetReceiveBufferLength(TInt(*param));
   552 				}
   553 				break;
   554 
   555 			case COMMIOCTL_GETBUFFERLENGTH:
   556 				{
   557 				int* param =REINTERPRET_CAST(int*,aParam);
   558 				*param = iCommPort.ReceiveBufferLength();
   559 				}
   560 				break;
   561 
   562 			case COMMIOCTL_NOTIFYSUPPORTED:
   563 				{
   564 				int* param =REINTERPRET_CAST(int*,aParam);
   565 				*param = NotifiesSupported();
   566 				}
   567 				break;
   568 
   569 			case REAL_COMMIOCTL_NOTIFY:
   570 				{
   571 				int* param =REINTERPRET_CAST(int*,aParam);
   572 				//if they are supported
   573 				if (RequestedNotifiesSupported(*param))
   574 					{
   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);
   582 
   583 					iDataAvailableNotifier = NULL;
   584 					iOutputEmptyNotifier = NULL;
   585 					iBreakNotifier = NULL;
   586 					iSignalsNotifier = NULL;
   587 					iErrorsNotifier = NULL;
   588 
   589 					TRAPD(tRes,
   590 						{
   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);
   596 						});
   597 					
   598 					if (KErrNone == tRes)
   599 						{
   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));
   606 
   607 						iRequestedSignals = *param;
   608 						iNotifyParamPtr = REINTERPRET_CAST(unsigned int*,aParam);
   609 						iNotifyStatus = &aStatus;
   610 						aStatus = KRequestPending;
   611 						return;			//on an async call here
   612 						}
   613 					else
   614 						{
   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;
   627 						ret = tRes;
   628 						}
   629 
   630 					}
   631 				else
   632 					{
   633 					ret = KErrNotSupported;
   634 					*param &=~NotifiesSupported();
   635 					}
   636 				}
   637 				break;
   638 
   639 				
   640 			default:
   641 				ret=KErrNotSupported;
   642 				break;
   643 			}
   644 		}
   645 		else
   646 			ret = KErrArgument;
   647  
   648 	Complete(aStatus,ret);
   649 	}
   650 
   651 
   652 TInt CSerialDesc::IoctlCompletion(int /*aCmd*/, void* /*aParam*/, TInt aStatus)
   653 	{
   654 	return aStatus;
   655 	}
   656 
   657 
   658 void CSerialDesc::ReadCancel()
   659 	{
   660 	iCommPort.ReadCancel();
   661 	}
   662 
   663 
   664 void CSerialDesc::IoctlCancel()
   665 	{
   666 	//stop the ioctl if in progress
   667 	CancelNotifiers(NULL);
   668 
   669 	if (iNotifyStatus)
   670 		{
   671 		iNotifyParamPtr[0] = 0;
   672 		Complete(*iNotifyStatus, -3);
   673 		}
   674 
   675 	}
   676 
   677 TInt CSerialDesc::ReadCompletion (TDes8& /*aBuf*/, TInt aStatus)
   678 	{
   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.
   682 	
   683 	if ((aStatus < 0) && (iRequestedSignals&(KNotifyFramingError|KNotifyOverrunError|KNotifyParityError)))	//we have a signal outstanding we can deal with here
   684 		{
   685 		switch (aStatus)
   686 			{
   687 			case KErrCommsFrame:	//comms framing error
   688 				if (iRequestedSignals&KNotifyFramingError)
   689 					Notify(KNotifyFramingError);
   690 				break;
   691 
   692 			case KErrCommsOverrun:	//comms overrrun error
   693  				if (iRequestedSignals&KNotifyOverrunError)
   694 					Notify(KNotifyOverrunError);
   695 				break;
   696 
   697 			case KErrCommsParity:	//comms parity error
   698  				if (iRequestedSignals&KNotifyParityError)
   699 					Notify(KNotifyParityError);
   700 				break;
   701 			
   702 			default:
   703 				//an error we don't signal
   704 				break;
   705 
   706 			}
   707 		}
   708 	
   709 	return aStatus;
   710 	}
   711 
   712 TBool CSerialDesc::RequestedNotifiesSupported(TInt aRequested)
   713 	{
   714 	//return true if these notifies are OK.  0 if any of them are illegal
   715 
   716 	TInt mask = ~(NotifiesSupported());
   717 	return !(aRequested&mask);
   718 	}
   719 
   720 TInt CSerialDesc::NotifiesSupported()
   721 	{
   722 	//return which notifies are supported.
   723 	//looks like the driver/server is going to have to be interrogated here
   724 
   725 	//start with the ones we can fake
   726 	TInt supported = KNotifyFramingError|KNotifyOverrunError|KNotifyParityError;
   727 	
   728 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
   729 	//get the supported ones from C32
   730 	TCommCaps2 devCap;
   731 	TCommCapsV02& deviceCapabilities = devCap();
   732 	deviceCapabilities.iNotificationCaps = 0;
   733 	iCommPort.Caps(devCap);
   734 
   735 
   736 	//signals
   737 	if (deviceCapabilities.iNotificationCaps & KNotifySignalsChangeSupported)
   738 		supported |= (KNotifyCD|KNotifyCTS|KNotifyDSR|KNotifyRI);
   739 
   740 	//break interrupt
   741 	if (deviceCapabilities.iNotificationCaps & KNotifyBreakSupported)
   742 		supported |= KNotifyBreakInt;
   743 
   744 
   745 	//Data Available
   746 	if (deviceCapabilities.iNotificationCaps & KNotifyDataAvailableSupported)
   747 		supported |= KNotifyDataAvailable;
   748 
   749 	//Output Empty
   750 	if (deviceCapabilities.iNotificationCaps & KNotifyOutputEmptySupported)
   751 		supported |= KNotifyOutputEmpty;
   752 
   753 #endif  //ER5U_NOTIFICATION_SUPPORT_ONLY
   754 
   755 	return supported;
   756 	}
   757 
   758 void CSerialDesc::Notify(TInt aVal)
   759 	{
   760 	if (iErrorsNotifier)
   761 		{
   762 //		iNotifyParamPtr[0] = aVal;
   763 		*iRequestDataPtr = aVal;
   764 		iErrorsNotifier->Complete(0);
   765 		}
   766 	}
   767 
   768 
   769 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
   770 void CSerialDesc::NotifyDataAvailable(TRequestStatus& aStatus)
   771 	{
   772 	iCommPort.NotifyDataAvailable(aStatus);
   773 	}
   774 
   775 void CSerialDesc::NotifyDataAvailableCancel()
   776 	{
   777 	iCommPort.NotifyDataAvailableCancel();
   778 	}
   779 
   780 void CSerialDesc::NotifyOutputEmpty(TRequestStatus& aStatus)
   781 	{
   782 	iCommPort.NotifyOutputEmpty(aStatus);
   783 	}
   784 
   785 void CSerialDesc::NotifyOutputEmptyCancel()
   786 	{
   787 	iCommPort.NotifyOutputEmptyCancel();
   788 	}
   789 
   790 void CSerialDesc::NotifyBreak(TRequestStatus& aStatus)
   791 	{
   792 	iCommPort.NotifyBreak(aStatus);
   793 	}
   794 
   795 void CSerialDesc::NotifyBreakCancel()
   796 	{
   797 	iCommPort.NotifyBreakCancel();
   798 	}
   799 
   800 void CSerialDesc::NotifySignalChange(TRequestStatus& aStatus, TUint& aRequestData, TUint aSignalsMask)
   801 	{
   802 	iCommPort.NotifySignalChange(aStatus, aRequestData, aSignalsMask);
   803 	}
   804 
   805 void CSerialDesc::NotifySignalChangeCancel()
   806 	{
   807 	iCommPort.NotifySignalChangeCancel();
   808 	}
   809 #endif  //ER5U_NOTIFICATION_SUPPORT_ONLY
   810 
   811 void CSerialDesc::NotifyWriteErrors(TRequestStatus& aStatus, TUint* aRequestData, TUint aSignalsMask)
   812 	{
   813 	iRequestedSignals = aSignalsMask;
   814 	iRequestDataPtr = aRequestData;
   815 //	iNotifyParamPtr = aRequestData;
   816 	aStatus = KRequestPending;
   817 	}
   818 
   819 void CSerialDesc::NotifyWriteErrorsCancel()
   820 	{
   821 	iErrorsNotifier->Complete(KErrCancel);
   822 	}
   823 
   824 TUint CSerialDesc::Signals()
   825 	{
   826 	return iCommPort.Signals();
   827 	}
   828 
   829 
   830 void CSerialDesc::CancelNotifiers(const CNotifier* aCompletedNotifier)
   831 	{
   832 #ifndef ER5U_NOTIFICATION_SUPPORT_ONLY
   833 	if (iDataAvailableNotifier && (aCompletedNotifier != iDataAvailableNotifier))
   834 		{
   835 		iDataAvailableNotifier->Cancel();
   836 		delete iDataAvailableNotifier;
   837 		iDataAvailableNotifier = NULL;
   838 		}
   839 
   840 	if (iOutputEmptyNotifier && (aCompletedNotifier != iOutputEmptyNotifier))
   841 		{
   842 		iOutputEmptyNotifier->Cancel();
   843 		delete iOutputEmptyNotifier;
   844 		iOutputEmptyNotifier = NULL;
   845 		}
   846 	
   847 	if (iBreakNotifier && (aCompletedNotifier != iBreakNotifier))
   848 		{
   849 		iBreakNotifier->Cancel();
   850 		delete iBreakNotifier;
   851 		iBreakNotifier = NULL;
   852 		}
   853 
   854 
   855 	if (iSignalsNotifier && (aCompletedNotifier != iSignalsNotifier))
   856 		{
   857 		iSignalsNotifier->Cancel();
   858 		delete iSignalsNotifier;
   859 		iSignalsNotifier = NULL;
   860 		}
   861 #endif //ER5U_NOTIFICATION_SUPPORT_ONLY
   862 	if (iErrorsNotifier && (aCompletedNotifier != iErrorsNotifier))
   863 		{
   864 		iErrorsNotifier->Cancel();
   865 		delete iErrorsNotifier;
   866 		iErrorsNotifier = NULL;
   867 		}
   868 	}
   869