serialserver/c32serialserver/LOOPBACK/loopback.CPP
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     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 // This file implements a loopback driver for use with the ETel Regression test harness.  This
       
    15 // driver supports two ports with signalling capabilities for DCD, DSR, DTR, RTS, RI, and CTS.
       
    16 // In order for the signalling to function properly, one port should be opened as a DCE, though
       
    17 // the driver will allow both ports to operate as DTE's.
       
    18 // By default, the driver marks or asserts (sets to 1) the following signals when the method
       
    19 // SetRole is called.
       
    20 // For the DTE:
       
    21 // KSignalRTS	KSignalDTR
       
    22 // For the DCE:
       
    23 // KSignalCTS	KSignalDSR
       
    24 // Note that the DCE does NOT set DCD, thus it's initial state is space or de-asserted
       
    25 // (set to zero).  This was chosen because of the desire of test script authors to fully
       
    26 // control DCD.
       
    27 // The driver supports the following signalling configuration handshake capabilities:
       
    28 // For the DTE:
       
    29 // KCapsObeyCTSSupported  KCapsFailCTSSupported
       
    30 // KCapsObeyDSRSupported  KCapsFailDSRSupported
       
    31 // KCapsObeyDCDSupported  KCapsFailDCDSupported
       
    32 // For the DCE:
       
    33 // KCapsObeyRTSSupported  KCapsObeyDTRSupported
       
    34 // Break, Configuration Change Notification, Flow Control Notification, and Data Available
       
    35 // Notifications are not supported.
       
    36 // directory exists.  The log file is named loopback.
       
    37 // 
       
    38 //
       
    39 
       
    40 /**
       
    41  @file
       
    42  @note	This driver will create a log file in the Logs\ETel directory if the Logs\ETel
       
    43 */
       
    44 #include <cs_port.h>
       
    45 #include "LOGGER.H"
       
    46 #include <d32comm.h>
       
    47 #include <c32comm.h>
       
    48 #include <e32hal.h>
       
    49 #include <c32comm_internal.h>
       
    50 
       
    51 #ifdef __LOGGER__XTRA
       
    52 #define LOGI(AAA)	CETelLogger::WriteFormat(TRefByValue<const TDesC8>(AAA),iPortName,iSignals,&iPtr);
       
    53 #else
       
    54 #define LOGI(AAA)
       
    55 #endif
       
    56 
       
    57 #if defined(__VC32__) && _MSC_VER==1100
       
    58 // Disable MSVC++ 5.0 aggressive warnings about non-expansion of inline functions.
       
    59 #pragma warning(disable : 4710)	// function '...' not expanded
       
    60 #endif
       
    61 
       
    62 const TUint KCommLowUnit=0;
       
    63 const TUint KBufferGrowthIncrement=0x1000;
       
    64 const TUint KMaxBufferSize = 0x8000;
       
    65 
       
    66 // This should be even
       
    67 const TUint KLoopbackCount=8;
       
    68 
       
    69 
       
    70 #define SERIAL_DESCRIPTION _L("Loopback CSY")
       
    71 #define SERIAL_NAME _S("Loopback")
       
    72 
       
    73 // #define _DEBUG_CONSOLE_
       
    74 
       
    75 #if defined(_DEBUG_CONSOLE_)
       
    76 // This class is not used in the loopback csy.  It is left here for future reference.
       
    77 #include <e32twin.h>
       
    78 class RDebugConsole : public RConsole
       
    79 	{
       
    80 public:
       
    81 	RDebugConsole();
       
    82 public:
       
    83 	void Printf(TRefByValue<const TDesC> aFmt,...);
       
    84 	};
       
    85 
       
    86 #define DEBUG_TRACE(m) m
       
    87 
       
    88 #else	// (_DEBUG)
       
    89 
       
    90 #define DEBUG_TRACE(m)
       
    91 //
       
    92 #endif
       
    93 
       
    94 //
       
    95 // "Entry point object" makes the objects which do the work
       
    96 class CHWPort;
       
    97 
       
    98 
       
    99 /**
       
   100  * This class is the factory port object.  It drives the "entry point object" which
       
   101  * makes the reset of the objects do their work.  It is based on the basic serial port
       
   102  * class CSerial.
       
   103  */
       
   104 class CHWPortFactory : public CSerial
       
   105 	{
       
   106 public:
       
   107     CHWPortFactory();
       
   108     ~CHWPortFactory();
       
   109 	virtual CPort * NewPortL(const TUint aUnit);
       
   110 	virtual void Info(TSerialInfo &aSerialInfo);
       
   111 	void Remove(CHWPort* aPort);
       
   112 public: //CSerial
       
   113 	TSecurityPolicy PortPlatSecCapability(TUint aPort) const;
       
   114 private:
       
   115 
       
   116 	CHWPort* iPort[KLoopbackCount];	// pairs of ports
       
   117 	CHWPort* PairedPort(TUint aPort) { return iPort[aPort^1]; } // returns the other half
       
   118 
       
   119 	};
       
   120 
       
   121 
       
   122 /**
       
   123  *	This class is the object that interfaces with the commserver.  An instance of this class
       
   124  *	represents one port in the loopback driver.
       
   125  */
       
   126 class CHWPort : public CPort
       
   127 	{
       
   128 public:
       
   129 	static CHWPort * NewL(TUint aUnit);
       
   130 private:
       
   131 	 CHWPort();
       
   132 
       
   133 public:
       
   134 	virtual void StartRead(const TAny* aClientBuffer,TInt aLength);
       
   135 	virtual void ReadCancel();
       
   136 	virtual TInt QueryReceiveBuffer(TInt& aLength) const;
       
   137 	virtual void ResetBuffers(TUint aFlags);
       
   138 	virtual void StartWrite(const TAny* aClientBuffer,TInt aLength);
       
   139 	virtual void WriteCancel();
       
   140 	virtual void Break(TInt aTime);
       
   141 	virtual void BreakCancel();
       
   142 	virtual TInt GetConfig(TDes8& aDes) const;
       
   143 	virtual TInt SetConfig(const TDesC8& aDes);
       
   144 	virtual TInt SetServerConfig(const TDesC8& aDes);
       
   145 	virtual TInt GetServerConfig(TDes8& aDes);
       
   146 	virtual TInt GetCaps(TDes8& aDes);
       
   147 	virtual TInt GetSignals(TUint& aSignals);
       
   148 	virtual TInt SetSignalsToMark(TUint aSignals);
       
   149 	virtual TInt SetSignalsToSpace(TUint aSignals);
       
   150 	virtual TInt GetReceiveBufferLength(TInt& aLength) const;
       
   151 	virtual TInt SetReceiveBufferLength(TInt aSignals);
       
   152 	virtual void Destruct();
       
   153 	virtual void FreeMemory();
       
   154 	virtual void NotifySignalChange(TUint aSignalMask);
       
   155 	virtual void NotifySignalChangeCancel();
       
   156 	virtual void NotifyConfigChange();
       
   157 	virtual void NotifyConfigChangeCancel();
       
   158 	virtual void NotifyFlowControlChange();
       
   159 	virtual void NotifyFlowControlChangeCancel();
       
   160 	virtual void NotifyBreak();
       
   161 	virtual void NotifyBreakCancel();
       
   162 	virtual void NotifyDataAvailable();
       
   163 	virtual void NotifyDataAvailableCancel();
       
   164 	virtual void NotifyOutputEmpty();
       
   165 	virtual void NotifyOutputEmptyCancel();
       
   166 	virtual TInt GetFlowControlStatus(TFlowControl& aFlowControl);
       
   167 	virtual TInt GetRole(TCommRole& aRole);
       
   168 	virtual TInt SetRole(TCommRole aRole);
       
   169 
       
   170 	virtual ~CHWPort();
       
   171 #if defined (_DEBUG_DEVCOMM)
       
   172 	virtual void DoDumpDebugInfo(const RMessage2 &aMessage);
       
   173 #endif
       
   174 public:
       
   175 	void SetLoopbackPort(CHWPort* aHWPort);
       
   176 	TInt WriteBuf(const TAny* aClientBuffer,TInt aLength, TBool& aIssueComplete);
       
   177 	void TryToCompleteRead();
       
   178 	void UpdatePortResources();
       
   179 
       
   180 private:
       
   181 	void CheckSigsAndCompleteRead();
       
   182 public:
       
   183 	TPtr8 iPtr;				//< A pointer to the buffer created during class creation.
       
   184 
       
   185 private:
       
   186 	TCommRole iRole;		//< The role of this port (ECommRoleDTE or ECommRoleDCE)
       
   187 	TUint iSignals;			//< The current signals for this port
       
   188 	TUint iSignalMask;		//< The mask used when a NotifySignalChange request is posted.
       
   189 							//< If it is clear, no request is outstanding.  It is cleared when
       
   190 							//< a request is either cancelled or completed.
       
   191 
       
   192 	TBool iWritePending;			//< True if a write is left pending
       
   193 	TInt  iWritePendingLength;		//< The length of the buffer that was left pending.
       
   194 	const TAny* iClientWriteBuffer; //< The buffer pointer that was pended.  A pended write
       
   195 									//< implies that the WriteCompleted was NOT called when
       
   196 									//< the write was posted.
       
   197 
       
   198 	TPckgBuf<TCommServerConfigV01> iServerConfig;	//< A placeholder; no real function in loopback.
       
   199 	TPckgBuf<TCommConfigV01> iConfig;	//< The configuration of this port.  Important fields for
       
   200 										//< the loopback driver are: iHandShake
       
   201 
       
   202 	CHWPort* iLoopbackPort;	//< The pointer to the loopback port to which this port is connected.
       
   203 
       
   204 	/**
       
   205 	An HBufC created during port creation, pointed to by iPtr.
       
   206 	This buffer is only appended to by this object on a write request;
       
   207 	this object never reads from the buffer.  iLoopbackPort is the
       
   208 	object responsible for reading from this iBuf (via iPtr), and send
       
   209 	the data it reads to iLoopbackPort's client (as a completion of a
       
   210 	read request).
       
   211 	*/
       
   212 	HBufC8* iBuf;			//< An HBuf created during port creation, pointed to by iPtr.
       
   213 							//< Note that this buffer can grow during operation, but it will
       
   214 							//< not shrink.
       
   215 	TInt iBufSize;			//< The initial size of the buffer and it's growth increment.
       
   216 	TBool iReadPending;		//< Boolean indicating that a read has been left pending for later
       
   217 							//< completion.
       
   218 
       
   219 	TBool iReadOneOrMore;	//< Should the current read (even if it is pending) complete before
       
   220 							//< the buffer is full?
       
   221 
       
   222 	TBool iDataNotify;		//< Set when a data notify event is pending
       
   223 
       
   224 	TInt iBytesWritten;		//< The number of bytes written to the current read buffer.
       
   225 	TInt iPendingLength;	//< Count of how many more bytes can be written to the read buffer
       
   226 	/**
       
   227 	Pointer to the client buffer to be filled by a read.  The read
       
   228 	actually takes the data from iLoopbackPort->iPtr to send to the
       
   229 	client.
       
   230 	*/
       
   231 	const TAny* iClientReadBuffer;		//< Pointer to the client buffer to be filled by a read.
       
   232 
       
   233 	TUint iPortName;		//< Unit number of this port
       
   234 
       
   235 #if defined (_DEBUG_CONSOLE_)
       
   236 	// Not used in the current loopback driver.
       
   237 #if defined (_DEBUG_DEVCOMM)
       
   238 	CCommDebugDumper *iDumper;		//< Pointer to debug class.
       
   239 #endif
       
   240 public:
       
   241 	RDebugConsole iConsole;			//< Console for debugging.
       
   242 #endif
       
   243 	};
       
   244 
       
   245 //
       
   246 // CHWPort definitions
       
   247 //
       
   248 CHWPort::CHWPort() : iPtr(NULL,0,0)
       
   249 /**
       
   250  * This method is the basic constructor for the CHWPort class.  In initializes
       
   251  * the iPtr member specifically to NULL.
       
   252  *
       
   253  * @param	None
       
   254  *
       
   255  * @return	None
       
   256  */
       
   257 	{
       
   258 	__DECLARE_NAME(_S("CHWPort"));
       
   259 	}
       
   260 
       
   261 void CloseObject(TAny* anObject)
       
   262 /**
       
   263  * This method simply closes an object from the cleanup stack.  The object must contain
       
   264  * a Close method.
       
   265  *
       
   266  * @param	anObject - a TAny pointer to the object to close.
       
   267  * @return	None
       
   268  */
       
   269 	{
       
   270 	((CObject*)anObject)->Close();
       
   271 	}
       
   272 
       
   273 CHWPort* CHWPort::NewL(TUint aUnit)
       
   274 /**
       
   275  * This method is used by the factory object to create the new CHWPort instances.
       
   276  * After newing the CHWPort object, the buffer is created, roles and signals are defaulted,
       
   277  * and names are initialized.
       
   278  *
       
   279  * @param	aUnit - the unit to create.
       
   280  *
       
   281  * @return	A pointer to the created object
       
   282  */
       
   283 	{
       
   284 
       
   285 	LOGTEXTREL(_S8("Loopback:NewL: Called"));
       
   286 	LOGTEXTREL2(_L8("Loopback:NewL:  Unit %d..."), aUnit);
       
   287 
       
   288 	CHWPort *p=new(ELeave) CHWPort;
       
   289 	TCleanupItem closePort(CloseObject,p);
       
   290 
       
   291 	CleanupStack::PushL(closePort);
       
   292 
       
   293 
       
   294 	p->iBuf=HBufC8::NewL(KBufferGrowthIncrement);
       
   295 	p->iBufSize=KBufferGrowthIncrement;
       
   296 	p->iPtr.Set((TUint8*)p->iBuf->Ptr(),0,KBufferGrowthIncrement);
       
   297 
       
   298 	p->iRole = ECommRoleDTE;
       
   299 	p->iSignals = 0;		// start with no signals asserted.
       
   300 	p->iSignalMask = 0;		// Prevents any spurrious notifications, etc.
       
   301 
       
   302 	TName name;
       
   303 	name.Format(_L("%d"),aUnit);
       
   304 	p->SetName(&name);
       
   305 	p->iPortName = aUnit;
       
   306 #if defined (_DEBUG_CONSOLE_)
       
   307 	name.Format(_L("Comm::%d"),aUnit);
       
   308 	p->iConsole.SetTitle(name);
       
   309 #if defined (_DEBUG_DEVCOMM)
       
   310 	p->iDumper=CCommDebugDumper::NewL(p->iConsole);
       
   311 #endif
       
   312 #endif
       
   313 	CleanupStack::Pop();
       
   314 
       
   315 	return p;
       
   316 	}
       
   317 
       
   318 void CHWPort::SetLoopbackPort(CHWPort* aHWPort)
       
   319 /**
       
   320  * This method sets up the loopback port member of the CHWPort.  It is used after
       
   321  * both ports have been created (NewL).  This allows each port to "know" to whom he is
       
   322  * connected.
       
   323  *
       
   324  * @param	aHWPort - the port which THIS port should be connected to.
       
   325  *
       
   326  * @return	None
       
   327  */
       
   328 	{
       
   329 	if (aHWPort != NULL)
       
   330 		{
       
   331 		LOGTEXT3(_L8("SetLoopbackPort:  Unit %d-%d"), iPortName, aHWPort->iPortName);
       
   332 		}
       
   333 	else
       
   334 		{
       
   335 		LOGTEXT2(_L8("Loopback:SetLoopbackPort:  Unit %d..."), iPortName);
       
   336 		}
       
   337 
       
   338 	// Now set up the loopback
       
   339 	iLoopbackPort=aHWPort;
       
   340 
       
   341 	}
       
   342 
       
   343 
       
   344 void CHWPort::CheckSigsAndCompleteRead()
       
   345 /**
       
   346  * This method checks the configuration of the port and the current state of the signals
       
   347  * and determines if the read should even attempt to be completed.  Based on configurations,
       
   348  * reads can fail or be left pending (KConfigObeyXXX).  This method calls TryToCompleteRead
       
   349  * if all configuration and signal state allows the read to continue.
       
   350  *
       
   351  * Note that this method is called to either complete a pended read (from WriteBuf) or
       
   352  * to complete an incoming read request (from StartRead).  Also note that this routine does
       
   353  * not check the fail flags.  These flags are checked when the read is first posted and
       
   354  * when the signals are first asserted/deasserted.  It is unnecessary (and maybe even undesirable)
       
   355  * to check the fail flags here.
       
   356  *
       
   357  * @param	None
       
   358  *
       
   359  * @return	None
       
   360  */
       
   361 	{
       
   362 	LOGI(_L8("CheckSigsAndCompleteRead:%04d %x \"%S\""));
       
   363 
       
   364 	LOGTEXT2(_L8("Loopback:CheckSigsAndCompleteRead:  Unit %d..."), iPortName);
       
   365 
       
   366 
       
   367 	// At this point, we must check the config flags and signals.  If we have been
       
   368 	// configured to obey signals, then we must pend the read and not complete it.
       
   369 	// Note that the iReadPending flag was set in StartRead().
       
   370 	if (ECommRoleDTE == iRole)
       
   371 		{
       
   372 		if (((iConfig().iHandshake & KConfigObeyDCD) && (!(iSignals & KSignalDCD))) ||
       
   373 			((iConfig().iHandshake & KConfigObeyDSR) && (!(iSignals & KSignalDSR))))
       
   374 			{
       
   375 			LOGI(_L8("CheckSigsAndCompleteRead DTE:%04d %x \"%S\""));
       
   376 			return;
       
   377 			}
       
   378 		}
       
   379 	else if (ECommRoleDCE == iRole)
       
   380 		{
       
   381 		if ((iConfig().iHandshake & (KConfigObeyDTR)) && (!(iSignals & (KSignalDTR))))
       
   382 			{
       
   383 			LOGI(_L8("CheckSigsAndCompleteRead DCE:%04d %x \"%S\""));
       
   384 			return;
       
   385 			}
       
   386 		}
       
   387 
       
   388 
       
   389 	// Can the request be satisfied now?  Note that we call TryToCompleteRead on THIS instance.
       
   390 	// This means that CheckSigsAndCompleteRead must be called on the desired instance.
       
   391 	TryToCompleteRead();
       
   392 	LOGI(_L8("CheckSigsAndCompleteRead:%04d %x \"%S\""));
       
   393 	}
       
   394 
       
   395 
       
   396 void CHWPort::StartRead(const TAny* aClientBuffer,TInt aLength)
       
   397 /**
       
   398  * This method queues a read operation to the driver.  If the read length is zero (which is a
       
   399  * special case used during initialization) the read completes immediately without being
       
   400  * concerned about any of the configuration flags.  Failure flags are checked in this routine.
       
   401  * If the port has been configured to fail (KConfigFailXXX) and the signals are NOT asserted,
       
   402  * then the read will fail immediately with KErrCommsLineFail.  Obey flags are not handled here,
       
   403  * but are handled in a different method.  The code was structured in this manner so that the
       
   404  * Obey flags are checked any time a read is attempted to be completed, not just when the read
       
   405  * is initially sent to the driver.  This is needed because reads can pend and before the reads
       
   406  * are completed the signal state could change.
       
   407  *
       
   408  * @param	aClientBuffer	- a TAny * to the buffer into which data is placed.
       
   409  * @param	aLength			- the length of the buffer.  If the length is less than zero the
       
   410  *                            read can be completed with less than length bytes available.  If
       
   411  *                            a positive length value is specified, the read will not complete
       
   412  *                            until length bytes have been read.
       
   413  *
       
   414  * @return	None
       
   415  */
       
   416 	{
       
   417 
       
   418 	//	DEBUG_TRACE((iConsole.Write(_L("DoRead \n\r"))));
       
   419 	LOGI(_L8("LOGIStartRead:%04d %x \"%S\""));
       
   420 
       
   421 	LOGTEXT2(_L8("Loopback:StartRead:  Unit %d..."), iPortName);
       
   422 
       
   423 	// Because a length of zero is a special case, we will complete this without
       
   424 	// worries about the config/fail flags.
       
   425 	if(aLength==0)
       
   426 		{
       
   427 		ReadCompleted(KErrNone);
       
   428 
       
   429 		LOGI(_L8("StartRead 0:%04d %x \"%S\""));
       
   430 
       
   431 		return;
       
   432 		}
       
   433 
       
   434 
       
   435 	// At this point, we must check the config flags and signals.  If we have been
       
   436 	// configured to fail operations if certain signals are not set, then we must
       
   437 	// fail the read.
       
   438 	if (ECommRoleDTE == iRole)
       
   439 		{
       
   440 		if (((iConfig().iHandshake & KConfigFailDCD) && (!(iSignals & KSignalDCD))) ||
       
   441 			((iConfig().iHandshake & KConfigFailDSR) && (!(iSignals & KSignalDSR))))
       
   442 			{
       
   443 			ReadCompleted(KErrCommsLineFail);
       
   444 			LOGI(_L8("XtartRead DTE:%04d %x \"%S\""));
       
   445 			return;
       
   446 			}
       
   447 		}
       
   448 	else if (ECommRoleDCE == iRole)
       
   449 		{
       
   450 		if ((iConfig().iHandshake & (KConfigFailDTR)) && (!(iSignals & (KSignalDTR))))
       
   451 			{
       
   452 			ReadCompleted(KErrCommsLineFail);
       
   453 			LOGI(_L8("StartRead DCE:%04d %x \"%S\""));
       
   454 			return;
       
   455 			}
       
   456 		}
       
   457 
       
   458 
       
   459 	// At this point, we set up for the read.  If the obey flags later don't let us
       
   460 	// complete the read, having this work done is vital.
       
   461 	iReadOneOrMore=EFalse;
       
   462 	if(aLength<0)
       
   463 		{
       
   464 		aLength=-aLength;
       
   465 		iReadOneOrMore=ETrue;
       
   466 		}
       
   467 
       
   468 	iBytesWritten=0;
       
   469 	iPendingLength=aLength;
       
   470 	iClientReadBuffer=aClientBuffer;
       
   471 	iReadPending=ETrue;
       
   472 
       
   473 	// Later code will assert iLoopback, so check it now to avoid crashes during startup.
       
   474 	// The CheckSigsAndCompeteRead method will actually process the Obey flags.
       
   475 	if (iLoopbackPort != NULL)
       
   476 		{
       
   477 		CheckSigsAndCompleteRead();
       
   478 		}
       
   479 
       
   480 	LOGI(_L8("StartRead:%04d %x \"%S\""));
       
   481 	}
       
   482 
       
   483 void CHWPort::ReadCancel()
       
   484 /**
       
   485  * Cancel a pending read and complete it with KErrCancel.  The handling of the CActive class
       
   486  * will by default complete any outstanding read with KErrCancel, but it is cleaner to handle
       
   487  * that processing here.
       
   488  *
       
   489  * @param	None
       
   490  *
       
   491  * @return	None
       
   492  */
       
   493 	{
       
   494 	LOGI(_L8("ReadCancel:%04d %x \"%S\""));
       
   495 
       
   496 	LOGTEXT2(_L8("Loopback:ReadCancel:  Unit %d..."), iPortName);
       
   497 
       
   498 	iReadPending=EFalse;
       
   499 
       
   500 	ReadCompleted(KErrCancel);
       
   501 
       
   502 	}
       
   503 
       
   504 
       
   505 TInt CHWPort::WriteBuf(const TAny* aClientBuffer,TInt aLength, TBool& aIssueComplete)
       
   506 /**
       
   507  * This method writes the client buffer to the loopback port.  It must take into consideration
       
   508  * all of the KConfigFailXXX and KConfigObeyXXX flags that might have been specified in the
       
   509  * configuration of the port.  Any fail configuration results with writes failing with the
       
   510  * KErrCommsLineFail error.  This method is used both when the write is originally posted to
       
   511  * the driver and when trying to finish any write that was pended by the driver based on the
       
   512  * Obey flags.  This routine does not actually complete the read, but returns a value with
       
   513  * which the caller should complete the read.  Because this routine can also leave the operation
       
   514  * pended, it uses the aIssueComplete boolean to tell the caller whether or not to complete the
       
   515  * read.
       
   516  *
       
   517  * @param	aClientBuffer	- a TAny * to the buffer which contains the data to write
       
   518  * @param	aLength			- the length of the buffer.
       
   519  * @param	aIssueComplete	- a reference to a boolean used to indicate to the caller if the
       
   520  *                            write operation should be completed.
       
   521  *							- ETrue  - Caller should issue the WriteCompleted with returned
       
   522  *							           result code.
       
   523  *							- EFalse - Caller shoud not issue the WriteCompleted.
       
   524  *
       
   525  * @return	KErrNone		- Everything is okay
       
   526  * @return	KErrCommsLineFail  - Write failed based on signal state and configuration.
       
   527  * @return	Varies			- Non-Zero return from Kernel calls
       
   528  */
       
   529 
       
   530 	{
       
   531 	TInt res=KErrNone;
       
   532 
       
   533 	LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   534 
       
   535 	// Plan on completeing, so set aIssueComplete to TRUE.
       
   536 	aIssueComplete = ETrue;
       
   537 
       
   538 
       
   539 	LOGTEXT3(_L8("Config 0x%x  Sigs 0x%x"), iConfig().iHandshake, iSignals);
       
   540 
       
   541 	// At this point, we must check the config flags and signals.  Note that Fail
       
   542 	// flags always take precedence over Obey flags.
       
   543 	if (ECommRoleDTE == iRole)
       
   544 		{
       
   545 		// if we are configured to fail if CD, DSR, or CTS are not present, then we
       
   546 		// must fail the write here.
       
   547 		if (((iConfig().iHandshake & KConfigFailDCD) && (!(iSignals & KSignalDCD))) ||
       
   548 			((iConfig().iHandshake & KConfigFailDSR) && (!(iSignals & KSignalDSR))) ||
       
   549 			((iConfig().iHandshake & KConfigFailCTS) && (!(iSignals & KSignalCTS))))
       
   550 			{
       
   551 			LOGTEXT2(_L8("WriteBuf:  DTE Failure  Unit %d..."), iPortName);
       
   552 			LOGTEXT3(_L8("...Config 0x%x  Sigs 0x%x..."), (iConfig().iHandshake), iSignals);
       
   553 			res=KErrCommsLineFail;
       
   554 			LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   555 			return res;
       
   556 			}
       
   557 
       
   558 		// At this point, we must check the config flags and signals.  If we have been
       
   559 		// configured to obey signals, then we must pend the write and not complete the
       
   560 		// write.
       
   561 		if (((iConfig().iHandshake & KConfigObeyDCD) && (!(iSignals & KSignalDCD))) ||
       
   562 			((iConfig().iHandshake & KConfigObeyDSR) && (!(iSignals & KSignalDSR))) ||
       
   563 			((iConfig().iHandshake & KConfigObeyCTS) && (!(iSignals & KSignalCTS))))
       
   564 			{
       
   565 			LOGTEXT2(_L8("WriteBuf:  DTE Pended:  Unit %d..."), iPortName);
       
   566 			iWritePending = ETrue;
       
   567 			iClientWriteBuffer = aClientBuffer;
       
   568 			iWritePendingLength = aLength;
       
   569 			aIssueComplete = EFalse;
       
   570 			res=KErrNone;
       
   571 			LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   572 			return res;
       
   573 			}
       
   574 		}
       
   575 	else if (ECommRoleDCE == iRole)
       
   576 		{
       
   577 		// if we are configured to fail when DTR or RTS are not present, then
       
   578 		// fail the write here.
       
   579 		if (((iConfig().iHandshake & KConfigFailRTS) && (!(iSignals & KSignalRTS))) ||
       
   580 			((iConfig().iHandshake & KConfigFailDTR) && (!(iSignals & KSignalDTR))))
       
   581 			{
       
   582 			LOGTEXT2(_L8("WriteBuf:  DCE Failure...  Unit %d..."), iPortName);
       
   583 			LOGTEXT3(_L8("...Config 0x%x  Sigs 0x%x..."), (iConfig().iHandshake), iSignals);
       
   584 			res=KErrCommsLineFail;
       
   585 			LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   586 			return res;
       
   587 			}
       
   588 
       
   589 		// At this point, we must check the config flags and signals.  If we have been
       
   590 		// configured to obey signals, then we must pend the write and not complete the
       
   591 		// write.
       
   592 		if (((iConfig().iHandshake & KConfigObeyRTS) && (!(iSignals & KSignalRTS))) ||
       
   593 			((iConfig().iHandshake & KConfigObeyDTR) && (!(iSignals & KSignalDTR))))
       
   594 			{
       
   595 			LOGTEXT2(_L8("WriteBuf:  DCE Pended:  Unit %d..."), iPortName);
       
   596 			LOGTEXT3(_L8("...Config 0x%x  Sigs 0x%x..."), (iConfig().iHandshake), iSignals);
       
   597 			iWritePending = ETrue;
       
   598 			iClientWriteBuffer = aClientBuffer;
       
   599 			iWritePendingLength = aLength;
       
   600 			aIssueComplete = EFalse;
       
   601 			res=KErrNone;
       
   602 			LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   603 			return res;
       
   604 			}
       
   605 		}
       
   606 
       
   607 	// Resize the receiving buffer if it is not big enough or it is
       
   608 	// more than twice as big as it needs to be for this write.
       
   609 	if ((iPtr.Length() + aLength) > iBufSize)
       
   610 		{
       
   611 		// New buffer size will be just big enough to fit the existing
       
   612 		// data + new data, rounded up to nearest multiple of
       
   613 		// KBufferGrowthIncrement.
       
   614 		TInt newBufSize;
       
   615 
       
   616 		if (((iPtr.Length() + aLength) % KBufferGrowthIncrement) == 0)
       
   617 			{
       
   618 			newBufSize = iPtr.Length() + aLength;
       
   619 
       
   620 			}
       
   621 		else
       
   622 			{
       
   623 			// New buffer size = length of data already in the buffer
       
   624 			//					 + length of data to be added to the buffer
       
   625 			//					 + round up to next KBufferGrowthIncrement
       
   626 			newBufSize = iPtr.Length() + aLength
       
   627 						 + KBufferGrowthIncrement - ((iPtr.Length() + aLength)%KBufferGrowthIncrement);
       
   628 			}
       
   629 
       
   630 
       
   631 		// Need to resize the buffer
       
   632 		// Note: iBuf should not be deleted, buffer may be emptied
       
   633 		//       later if this ReAllocL fails and tmpBuffer remains NULL.
       
   634 	    HBufC8* tmpBuffer = NULL;
       
   635 	    TRAP(res, tmpBuffer = iBuf->ReAllocL(newBufSize));
       
   636 
       
   637 		if (tmpBuffer == NULL || res != KErrNone)
       
   638 			{
       
   639 			// Could not reallocate the buffer (maybe not enough
       
   640 			// memory) so write request fails.
       
   641 			iWritePending = EFalse;
       
   642 
       
   643 			// return with an Issue complete and an error message
       
   644 			aIssueComplete = ETrue;
       
   645 			LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   646 			return KErrNoMemory;
       
   647 			}
       
   648 
       
   649 		iBufSize = newBufSize;
       
   650 		iBuf = tmpBuffer;
       
   651 
       
   652 
       
   653 		// Note: the aIssueComplete flag has already been set to ETrue
       
   654 		// so, don't need to set it again here.
       
   655 		iWritePending = EFalse;
       
   656 		}
       
   657 
       
   658 	// Fill the receiving buffer
       
   659 	if (aLength!=0)
       
   660 		{
       
   661 		// point to where the new data will be located in our buffer
       
   662 		TPtr8 ptrWriteLocation((TUint8*)(iBuf->Ptr() + iPtr.Length()), aLength);
       
   663 
       
   664 		res = IPCRead(aClientBuffer,ptrWriteLocation);  // Must go through correct port
       
   665 
       
   666 		LOGTEXT2(_L8("Read \"%S\""), &ptrWriteLocation);
       
   667 		if(res!=KErrNone)
       
   668 			{
       
   669 			LOGI(_L8("WriteBuf:%04d %x \"%S\""));
       
   670 			return res;
       
   671 			}
       
   672 
       
   673 		// memory leak detection : we create a single memory leak, if our input buffer contains
       
   674 		// special token string:
       
   675 		_LIT8(KMemLeakToken, "--MemoryLeakToken--");
       
   676 		TInt nRetVal = ptrWriteLocation.Compare(KMemLeakToken);
       
   677 		if (nRetVal == 0)
       
   678 			{
       
   679             // coverity [returned_pointer]
       
   680 			// coverity [memory_leak] - create a memory leak intentionally, look at the comments above 
       
   681             TInt* pArr = new TInt[1024]; // deliberatly causing a memory leak here...
       
   682 			}
       
   683 
       
   684 		// set the iPtr to point to the new iBuffer and keep a record of data length
       
   685 		iPtr.Set((TUint8*)iBuf->Ptr(), iPtr.Length() + aLength, iBufSize);
       
   686 		}
       
   687 	// Since we are completing a write on THIS instance, see if we can complete a read on
       
   688 	// the loopback port.  A read could have been left pending.
       
   689 	if (iLoopbackPort != NULL)
       
   690 		{
       
   691 		iLoopbackPort->CheckSigsAndCompleteRead();
       
   692 		}
       
   693 
       
   694 	return res;
       
   695 	}
       
   696 
       
   697 void CHWPort::TryToCompleteRead()
       
   698 /**
       
   699  * This method attempts to complete reads, either as they are initially issued or at a later
       
   700  * time because they were pended when initially issued.  Data is moved from the buffer associated
       
   701  * with this port to a buffer that was supplied by the client when the read is issued.  The
       
   702  * read is completed when either the client buffer is full or when some data has been written
       
   703  * to the client buffer and the iReadOneOrMore member set.  This member data is set when then
       
   704  * initial read was passed a negative length value.  Using this method allows a read to complete
       
   705  * without filling the entire buffer.
       
   706  *
       
   707  * @param	None
       
   708  *
       
   709  * @return	None
       
   710  */
       
   711 
       
   712 	{
       
   713 	LOGI(_L8("TryToCompleteRead:%04d %x \"%S\""));
       
   714 
       
   715 	LOGTEXT2(_L8("Loopback:TryToCompleteRead: Unit %d ..."), iPortName);
       
   716 
       
   717 	ASSERT(iLoopbackPort);
       
   718 	TPtr8& refLoopBackiPtr = iLoopbackPort->iPtr; // Loopback listening port's buffer
       
   719 
       
   720 	// Is there a Data Available notification pending?
       
   721 	TInt s = refLoopBackiPtr.Length();
       
   722 	if(iDataNotify)
       
   723 		{
       
   724 		NotifyDataAvailableCompleted(KErrNone);
       
   725 		iDataNotify=EFalse;
       
   726 		}
       
   727 
       
   728 	// Is there a Read Pending?
       
   729 	if(!iReadPending)
       
   730 		return;
       
   731 
       
   732 	// If there's somthing in the buffer then try to copy that...
       
   733 	TInt stillToBeWritten=iPendingLength-iBytesWritten;
       
   734 	TInt len=Min(s, stillToBeWritten);
       
   735 
       
   736 	// only point to the data we are going to read
       
   737 	TPtrC8 ptr(refLoopBackiPtr.Ptr(), len);
       
   738 
       
   739 	LOGTEXT2(_L8("Write \"%S\""), &ptr);
       
   740 
       
   741 	// Search for terminator characters
       
   742 	TBool terminatorFound = EFalse;
       
   743 	const TText8* terminators = iConfig().iTerminator;
       
   744 	TInt termNum;
       
   745 	for (termNum=0; termNum < iConfig().iTerminatorCount; ++termNum)
       
   746 		{
       
   747 		TInt termIndex = ptr.Locate(terminators[termNum]);
       
   748 		if (termIndex >= 0)
       
   749 			{
       
   750 			// Found the terminator; reduce the length of ptr and search for the next one
       
   751 			len = termIndex + 1;
       
   752 			ptr.Set(refLoopBackiPtr.Ptr(), len);
       
   753 			terminatorFound = ETrue;
       
   754 			}
       
   755 		}
       
   756 
       
   757 	TInt res=IPCWrite(iClientReadBuffer,ptr,iBytesWritten);
       
   758 	if(res == KErrNone)
       
   759 		{
       
   760 		// Delete the read data from the buffer
       
   761 		ASSERT(refLoopBackiPtr.Length() >= len);
       
   762 		TPtrC8 source = refLoopBackiPtr.Right(refLoopBackiPtr.Length() - len);
       
   763 		// a memory move occurs on each read. This must be inefficient
       
   764 		refLoopBackiPtr.Copy(source);
       
   765 		iBytesWritten+=len;
       
   766 		}
       
   767 
       
   768 	if((iBytesWritten==iPendingLength)||(iReadOneOrMore&&(s>=1))||terminatorFound)
       
   769 		{
       
   770 		LOGTEXT2(_L8("Loopback:TryToCompleteRead: Completing Read  Unit %d ..."), iPortName);
       
   771 		iReadPending=EFalse;
       
   772 		// a complete read has succeeded, now update the Ports memory usage
       
   773 		iLoopbackPort->UpdatePortResources();
       
   774 		ReadCompleted(res);
       
   775 		}
       
   776 	}
       
   777 
       
   778 void CHWPort::UpdatePortResources()
       
   779 /**
       
   780  * This method recalculate how much memory is actually required by a ports write buffer
       
   781  *
       
   782  * @param Not used
       
   783  *
       
   784  * @return None
       
   785  */
       
   786 	{
       
   787 	LOGTEXT2(_L8("Loopback:UpdatePortResources: Unit %d ..."), iPortName);
       
   788 
       
   789 
       
   790 	TInt newBufSize = 0;
       
   791 
       
   792 	// it is possible to have a length of 0 therefore we leave the buffer size
       
   793 	// to KBufferGrowthIncrement
       
   794 	if(iPtr.Length() > 0)
       
   795 		{
       
   796 		newBufSize = iPtr.Length() + KBufferGrowthIncrement - ((iPtr.Length()) % KBufferGrowthIncrement);
       
   797 		}
       
   798 	else
       
   799 		{
       
   800 		// the minimum buffer size is KBufferGrowthIncrement
       
   801 		newBufSize = KBufferGrowthIncrement;
       
   802 		}
       
   803 
       
   804 	// if the buffer needs changing then resize it otherwise leave as is
       
   805 	if(newBufSize != iBufSize)
       
   806 		{
       
   807 		TInt res = KErrNone;
       
   808 		// Shrink the buffer to the new size calculated above. If this fails we return leaving memory as it was
       
   809 		HBufC8* tmpBuffer = NULL;
       
   810 	    TRAP(res, tmpBuffer = iBuf->ReAllocL(newBufSize));
       
   811 
       
   812 		if (tmpBuffer == NULL || res != KErrNone)
       
   813 			{
       
   814 	   		// could not resize the buffer - return without modifying anything
       
   815 	   		return;
       
   816 			}
       
   817 
       
   818 		iBuf = tmpBuffer;
       
   819 		iBufSize = newBufSize;
       
   820 
       
   821 		// update the public interface to our buffer.
       
   822 		iPtr.Set((TUint8*)iBuf->Ptr(), iPtr.Length(), iBufSize);
       
   823 		}
       
   824 	}
       
   825 
       
   826 TInt CHWPort::QueryReceiveBuffer(TInt& aLength) const
       
   827 /**
       
   828  * This method returns the length of the buffer associated with this instance of the
       
   829  * port.
       
   830  *
       
   831  * @param	aLength			- a reference to return the length of the buffer.
       
   832  *
       
   833  * @return	KErrNone
       
   834  */
       
   835 	{
       
   836 	LOGTEXT2(_L8("Loopback:QueryReceiveBuffer:  Unit %d..."), iPortName);
       
   837 
       
   838 	aLength=iPtr.Length();
       
   839 	return KErrNone;
       
   840 	}
       
   841 
       
   842 void CHWPort::ResetBuffers(TUint)
       
   843 /**
       
   844  * This method resets the buffer used by this loopback port
       
   845  *
       
   846  * @note Note that most ResetBuffers methods derived from CPort allow a parameter for flags.
       
   847  * This ResetBuffers method does not.
       
   848  *
       
   849  * @param	Not Used
       
   850  *
       
   851  * @return	None
       
   852  */
       
   853 	{
       
   854 
       
   855 	LOGI(_L8("ResetBuffers:%04d %x \"%S\""));
       
   856 
       
   857 	LOGTEXT2(_L8("Loopback:ResetBuffers:  Unit %d..."), iPortName);
       
   858 
       
   859 	// reset the length of data to zero and update port resources
       
   860 	iPtr.Set((TUint8*)iBuf->Ptr(), 0, iBufSize);
       
   861 
       
   862 	// this method will perform any memory re-sizing required on the port
       
   863 	UpdatePortResources();
       
   864 	}
       
   865 
       
   866 void CHWPort::StartWrite(const TAny* aClientBuffer,TInt aLength)
       
   867 /**
       
   868  * This method queues a write operation to the driver.  This method is simply the outside
       
   869  * interface to the class for writing data.  It calls a private method to actually process
       
   870  * the write.  StartWrite passes a reference to a boolean value to the private routine that
       
   871  * indicates whether or not StartWrite should issue a WriteCompleted response.  This is necessary
       
   872  * because some combinations of signals and configuration can cause writes to be pended and
       
   873  * thus NOT completed.
       
   874  *
       
   875  * @param	aClientBuffer	- a TAny * to the buffer into which data should be read.
       
   876  * @param	aLength			- the length of the data to be written.
       
   877  *
       
   878  * @return	None
       
   879  */
       
   880 	{
       
   881 
       
   882 	LOGI(_L8("StartWrite:%04d %x \"%S\""));
       
   883 
       
   884 	LOGTEXT2(_L8("Loopback:StartWrite:  Unit %d..."), iPortName);
       
   885 
       
   886 	// memory leak detection mechanism:
       
   887 	// if special write buffer token is received is received, we create memory leak
       
   888 	// this condition is triggered, when working with "te_C32_leakdetection.script"
       
   889 
       
   890 	DEBUG_TRACE((iConsole.Write(_L("DoWrite \n\r"))));
       
   891 	TBool issueComplete = ETrue;
       
   892 
       
   893 	TInt res = KErrNone;
       
   894 
       
   895 	if((iPtr.Length() + aLength) > KMaxBufferSize)
       
   896 		{
       
   897 		// we are exceeding our buffer growth size. Do not process the
       
   898 		// write message
       
   899 		iWritePending = EFalse;
       
   900 		res = KErrNoMemory;
       
   901 		}
       
   902 	else
       
   903 		{
       
   904 		res = WriteBuf(aClientBuffer,aLength, issueComplete);
       
   905 		}
       
   906 
       
   907 	// Only complete the write if allowed to by WriteBuf.
       
   908 	if (issueComplete)
       
   909 		{
       
   910 		LOGTEXT2(_L8("Loopback:StartWrite:  Completing Write Unit %d..."), iPortName);
       
   911 		LOGTEXT2(_L8("Loopback:StartWrite:  Completing Write Unit %d..."), res);
       
   912 		WriteCompleted(res);
       
   913 		}
       
   914 
       
   915 	LOGI(_L8("StartWrite:%04d %x \"%S\""));
       
   916 
       
   917 	}
       
   918 
       
   919 void CHWPort::WriteCancel()
       
   920 /**
       
   921  * This method cancels a pending write and issues a WriteCompleted with the result
       
   922  * KErrCancel.  If no writes are pending, then this method simply returns.
       
   923  *
       
   924  * @param	None
       
   925  *
       
   926  * @return	None
       
   927  */
       
   928 
       
   929 	{
       
   930 
       
   931 	LOGI(_L8("WriteCancel:%04d %x \"%S\""));
       
   932 
       
   933 	LOGTEXT2(_L8("Loopback:WriteCancel:  Unit %d..."), iPortName);
       
   934 
       
   935 
       
   936 	// if there is a pending write (which could happen with the obey
       
   937 	// flags), then we have to cancel the write.
       
   938 	if (iWritePending)
       
   939 		{
       
   940 		iWritePending = EFalse;
       
   941 		WriteCompleted(KErrCancel);
       
   942 		}
       
   943 	}
       
   944 
       
   945 void CHWPort::Break(TInt /* aTime */)
       
   946 /**
       
   947  * This method is currently not implemented in the loopback driver as breaks are
       
   948  * not supported.
       
   949  *
       
   950  * @param	Not Used
       
   951  *
       
   952  * @return	None
       
   953  */
       
   954 
       
   955 //
       
   956 // Queue a Break
       
   957 //
       
   958 	{}
       
   959 
       
   960 void CHWPort::BreakCancel()
       
   961 /**
       
   962  * This method is currently not implemented in the loopback driver as breaks are
       
   963  * not supported.
       
   964  *
       
   965  * @param	None
       
   966  *
       
   967  * @return	None
       
   968  */
       
   969 //
       
   970 // Cancel a pending break
       
   971 //
       
   972 	{}
       
   973 
       
   974 TInt CHWPort::GetConfig(TDes8& aDes) const
       
   975 /**
       
   976  * This gets the current configuration from the loopback driver.
       
   977  *
       
   978  * @param	aDes	- a TDes8 reference to copy the configuration into.
       
   979  *
       
   980  * @return	KErrNone
       
   981  */
       
   982 	{
       
   983 
       
   984 	LOGI(_L8("GetConfig:%04d %x \"%S\""));
       
   985 
       
   986 	LOGTEXT2(_L8("Loopback:GetConfig:  Unit %d..."), iPortName);
       
   987 
       
   988 	aDes.Copy(iConfig);
       
   989 	return KErrNone;
       
   990 	}
       
   991 
       
   992 TInt CHWPort::SetConfig(const TDesC8& aDes)
       
   993 /**
       
   994  * This sets the current configuration for the loopback driver.  Note that
       
   995  * no error checking is done when setting the configuration.
       
   996  *
       
   997  * @param	aDes	- a TDes8 reference to copy the configuration from.
       
   998  *
       
   999  * @return	KErrNone
       
  1000  */
       
  1001 	{
       
  1002 
       
  1003 	LOGI(_L8("SetConfig:%04d %x \"%S\""));
       
  1004 
       
  1005 	LOGTEXT2(_L8("Loopback:SetConfig:  Unit %d..."), iPortName);
       
  1006 
       
  1007 	iConfig.Copy(aDes);
       
  1008 	return KErrNone;
       
  1009 	}
       
  1010 
       
  1011 TInt CHWPort::GetCaps(TDes8& aDes)
       
  1012 /**
       
  1013  * This gets the supported capabilities from the loopback driver.  The actual capabilities of
       
  1014  * the driver will vary based on the role the port is playing (DCE or DTE).  The loopback driver
       
  1015  * supports capabilities via TCommCapsV01 and TCommCapsV02.
       
  1016  *
       
  1017  * @param	aDes				- a TDes8 reference to copy the capabilities into.
       
  1018  *
       
  1019  * @return	KErrNone			- Everything is okay.
       
  1020  * @return	KErrNotSupported	- The length of the descriptor passed to this method indicates a
       
  1021  *                                capabilities structure which we don't support.
       
  1022  */
       
  1023 	{
       
  1024 
       
  1025 	LOGI(_L8("GetCaps:%04d %x \"%S\""));
       
  1026 
       
  1027 	LOGTEXT2(_L8("Loopback:GetCaps:  Unit %d..."), iPortName);
       
  1028 
       
  1029 	if(aDes.Length()==sizeof(TCommCapsV01))
       
  1030 		{
       
  1031 		TCommCapsV01* commcaps=(TCommCapsV01*)(aDes.Ptr());
       
  1032 
       
  1033 		// We've got all of these
       
  1034 		commcaps->iRate=0x3fffff;
       
  1035 		commcaps->iDataBits=0xf;
       
  1036 		commcaps->iStopBits=0x3;
       
  1037 		commcaps->iParity=0x1f;
       
  1038 		commcaps->iFifo=0x1;
       
  1039 
       
  1040 		if (ECommRoleDTE == iRole)
       
  1041 			{
       
  1042 			commcaps->iHandshake= KCapsObeyCTSSupported | KCapsFailCTSSupported |
       
  1043 			                      KCapsObeyDSRSupported | KCapsFailDSRSupported |
       
  1044 			                      KCapsObeyDCDSupported | KCapsFailDCDSupported;
       
  1045 			}
       
  1046 		else
       
  1047 			{
       
  1048 			commcaps->iHandshake= KCapsObeyRTSSupported | KCapsObeyDTRSupported;
       
  1049 			}
       
  1050 
       
  1051 		commcaps->iSignals=0x3f;
       
  1052 		commcaps->iSIR=0x0;
       
  1053 		return KErrNone;
       
  1054 		}
       
  1055 	else if(aDes.Length()==sizeof(TCommCapsV02))
       
  1056 		{
       
  1057 		TCommCapsV02* commcaps=(TCommCapsV02*)(aDes.Ptr());
       
  1058 	// We've got all of these
       
  1059 		commcaps->iRate=0x3fffff;
       
  1060 		commcaps->iDataBits=0xf;
       
  1061 		commcaps->iStopBits=0x3;
       
  1062 		commcaps->iParity=0x1f;
       
  1063 		commcaps->iFifo=0x1;
       
  1064 
       
  1065 		if (ECommRoleDTE == iRole)
       
  1066 			{
       
  1067 			commcaps->iHandshake= KCapsObeyCTSSupported | KCapsFailCTSSupported |
       
  1068 			                      KCapsObeyDSRSupported | KCapsFailDSRSupported |
       
  1069 			                      KCapsObeyDCDSupported | KCapsFailDCDSupported |
       
  1070 			                      KCapsFreeRTSSupported | KCapsFreeDTRSupported;
       
  1071 			}
       
  1072 		else
       
  1073 			{
       
  1074 			commcaps->iHandshake= KCapsObeyRTSSupported | KCapsObeyDTRSupported;
       
  1075 			}
       
  1076 
       
  1077 		commcaps->iSignals=0x3f;
       
  1078 		commcaps->iSIR=0x0;
       
  1079 		commcaps->iNotificationCaps=KNotifySignalsChangeSupported;
       
  1080 		commcaps->iRoleCaps=0x0;
       
  1081 		return KErrNone;
       
  1082 		}
       
  1083 	else
       
  1084 		return KErrNotSupported;
       
  1085 	}
       
  1086 
       
  1087 TInt CHWPort::SetServerConfig(const TDesC8& aDes)
       
  1088 /**
       
  1089  * This sets the current server configuration for the loopback driver.  The loopback driver
       
  1090  * stores this information but does nothing with it.
       
  1091  *
       
  1092  * @param	aDes	- a TDes8 reference to copy the configuration from.
       
  1093  *
       
  1094  * @return	KErrNone
       
  1095  */
       
  1096 	{
       
  1097 
       
  1098 	LOGI(_L8("SetServerConfig:%04d %x \"%S\""));
       
  1099 
       
  1100 	LOGTEXT2(_L8("Loopback:SetServerConfig:  Unit %d..."), iPortName);
       
  1101 
       
  1102 	iServerConfig.Copy(aDes);
       
  1103 	return KErrNone;
       
  1104 	}
       
  1105 
       
  1106 TInt CHWPort::GetServerConfig(TDes8& aDes)
       
  1107 /**
       
  1108  * This gets the current server configuration for the loopback driver.  The loopback driver
       
  1109  * stores this information but does nothing with it other than return it here.
       
  1110  *
       
  1111  * @param	aDes	- a TDes8 reference to copy the configuration to.
       
  1112  *
       
  1113  * @return	KErrNone
       
  1114  */
       
  1115 	{
       
  1116 
       
  1117 	LOGI(_L8("GetServerConfig:%04d %x \"%S\""));
       
  1118 
       
  1119 	LOGTEXT2(_L8("Loopback:GetServerConfig:  Unit %d..."), iPortName);
       
  1120 
       
  1121 	aDes.Copy(iServerConfig);
       
  1122 	return KErrNone;
       
  1123 	}
       
  1124 
       
  1125 TInt CHWPort::GetSignals(TUint& aSignals)
       
  1126 /**
       
  1127  * This method retrieves the current setting of the signals for THIS port.
       
  1128  *
       
  1129  * @param	aSignals	- A reference to a TUint to return the signal settings.
       
  1130  *
       
  1131  * @return	KErrNone
       
  1132  */
       
  1133 	{
       
  1134 
       
  1135 	LOGI(_L8("GetSignals:%04d %x \"%S\""));
       
  1136 
       
  1137 	LOGTEXT3(_L8("Loopback:GetSignals:  Unit %d... Sigs 0x%x"), iPortName, iSignals);
       
  1138 
       
  1139 	aSignals=iSignals;
       
  1140 	return KErrNone;
       
  1141 	}
       
  1142 
       
  1143 TInt CHWPort::SetSignalsToMark(TUint aSignals)
       
  1144 /**
       
  1145  * This method asserts the signals specified by the parameter aSignals.  In addition to
       
  1146  * simply asserting the signals, this routine will complete any signal notification requests
       
  1147  * that are outstanding.  After handling any signal notification requests, this routine will
       
  1148  * also update the signal state of it's partner loopback port.  The other port's signals are
       
  1149  * updated only if they are considered output signals for the role that this port is playing.
       
  1150  * For example, assume that a DTE port is setting the RTS signal.  It determines that RTS is
       
  1151  * an output signal for a DTE port, so it must propagate the signal to the DCE by calling
       
  1152  * this routine on the DCE instance of the port.  When the DCE instance runs, it sets RTS, then
       
  1153  * determines that RTS is NOT a DCE output signal, so it does NOT attempt to propagate the signal.
       
  1154  * It is NOT an error for a DCE port to call this routine with DTE output signals.  In fact,
       
  1155  * this behaviour is required in order to propagate signal settings from one port to the other.
       
  1156  *
       
  1157  * After propagating the signal settings, this method will attempt to complete reads and writes
       
  1158  * that have been outstanding, based on the changed signals and the configuration of the
       
  1159  * port.  For example, say that the DTE port had been configured to Obey CTS (i.e., to flow control
       
  1160  * when CTS is not asserted).  When the DCE asserts CTS, this signal would be propagated to the
       
  1161  * DTE port.  Then the DTE port would check the current configuration and note that CTS has
       
  1162  * been asserted.  At this point, there could be operations which were pended (because of the
       
  1163  * lack of CTS) that should be attempted.  This method will attempt these operations.
       
  1164  *
       
  1165  *
       
  1166  * @param	aSignals	- a bitmask specifying which signals to assert (See definition
       
  1167  *                        of KSignalDCD, KSignalCTS, etc. for bit values).
       
  1168  *
       
  1169  * @return	KErrNone
       
  1170  */
       
  1171 	{
       
  1172 
       
  1173 	TBool attemptRead = EFalse;
       
  1174 	TBool attemptWrite = EFalse;
       
  1175 	TUint sigsChanged;
       
  1176 	TUint tmpSigs;
       
  1177 
       
  1178 
       
  1179 
       
  1180 	LOGI(_L8("SetSignalsToMark:%04d %x \"%S\""));
       
  1181 
       
  1182 
       
  1183 	LOGTEXT3(_L8("Loopback:SetSignalsToMark:  Unit %d...Sigs 0x%x"), iPortName, aSignals);
       
  1184 
       
  1185 	// If no signals are passed in to set, then get out of here.  This is possible when
       
  1186 	// the upper layers have used the RComm::SetSignals interface.  This interface is used
       
  1187 	// to both space and mark signals with a single call.  Frequently, this interface is used
       
  1188 	// with one of the two masks set to zero.
       
  1189 	if (!aSignals)
       
  1190 		return KErrNone;
       
  1191 
       
  1192 	tmpSigs = iSignals;
       
  1193 	iSignals |= aSignals;
       
  1194 
       
  1195 	// sigsChanged contains only the signals changed by this operation, no history is contained.
       
  1196 	sigsChanged = (iSignals ^ tmpSigs);
       
  1197 
       
  1198 	// Only complete notifications if the changed sigs were specified in the mask.
       
  1199 	if (sigsChanged & iSignalMask)
       
  1200 		{
       
  1201 		// Notify people that the signals have changed.
       
  1202 		// Note that the KSignalChanged bits are stored in sigsChanged, but passed.
       
  1203 		// The tmpSigs value has the state of all the signals that they were interested in
       
  1204 		// as specified by the iSignalMask and the Changed flags.
       
  1205         tmpSigs = (((sigsChanged & iSignalMask) * KSignalChanged) | (iSignals & iSignalMask));
       
  1206 		SignalChangeCompleted(tmpSigs, KErrNone);
       
  1207 		// Reset signal mask, another NotifiySignalChange is necessary to get any
       
  1208 		// more signal information out of the driver.
       
  1209 		iSignalMask = 0;
       
  1210 		}
       
  1211 
       
  1212 	// if I'm a DTE port and the signals changed are DTE outputs, then
       
  1213     // I've got to figure out what signals to change on the DCE side (as inputs).
       
  1214  	// else if I'm a DCE port and the signals changed are DCE outputs, then
       
  1215     // I've got to figure out what DTE signals I've got to change.
       
  1216     if ((ECommRoleDTE == iRole) && (sigsChanged & KSignalDTEOutputs))
       
  1217 		{
       
  1218 		if (iLoopbackPort)
       
  1219 			iLoopbackPort->SetSignalsToMark(aSignals);
       
  1220         }
       
  1221 	else if ((ECommRoleDCE == iRole) && (sigsChanged  & KSignalDCEOutputs))
       
  1222 		{
       
  1223 		if (iLoopbackPort)
       
  1224 			iLoopbackPort->SetSignalsToMark(aSignals);
       
  1225 		}
       
  1226 
       
  1227 
       
  1228 	// if we dropped DCD, CTS, or DSR, then we need to complete any outstanding writes and
       
  1229     // reads on the DTE port if they have been configured to fail.
       
  1230 	// We only look at the DTE input signals to see if the roles, etc. change.
       
  1231 	if (ECommRoleDTE == iRole)
       
  1232 		{
       
  1233 
       
  1234 		// DCD and DSR affect both Reads and Writes, so we'll want to attempt both
       
  1235 		// reads and writes later.
       
  1236 		if (((iConfig().iHandshake & KConfigObeyDCD) && (sigsChanged & KSignalDCD)) ||
       
  1237 			((iConfig().iHandshake & KConfigObeyDSR) && (sigsChanged & KSignalDSR)))
       
  1238 			{
       
  1239 			attemptRead = attemptWrite = ETrue;
       
  1240 			}
       
  1241 
       
  1242 		// CTS has NO effect on the Reads, so don't attempt to complete any reads here.
       
  1243 		// No need to do this if we executed the above if ...
       
  1244 		else if (((iConfig().iHandshake & KConfigObeyCTS) && (sigsChanged & KSignalCTS)))
       
  1245 			{
       
  1246 			attemptWrite = ETrue;
       
  1247 			}
       
  1248 		}
       
  1249 	// if the DTE dropped the signals (RTS and DTR) the complete actions for the DCE
       
  1250 	// only look at the DCE input signals.
       
  1251 	else if (ECommRoleDCE == iRole)
       
  1252 		{
       
  1253 		// if DTR has changed, then we need to try to complete both reads and writes.
       
  1254 		if (((iConfig().iHandshake & KConfigObeyDTR) && (sigsChanged & KSignalDTR)))
       
  1255 			{
       
  1256 			attemptRead = attemptWrite = ETrue;
       
  1257 			}
       
  1258 		// if RTS has changed, only attempt the Writes, RTS does not effect Reads.
       
  1259 		// No need to do this if we executed the above if ...
       
  1260 		else if (((iConfig().iHandshake & KConfigObeyRTS) && (sigsChanged & KSignalRTS)))
       
  1261 			{
       
  1262 			attemptWrite = ETrue;
       
  1263 			}
       
  1264 
       
  1265 		}
       
  1266 
       
  1267     // Attempt to complete any writes if necessary.  Note that if we do a write for THIS
       
  1268 	// port, it will attempt to complete a read for the Loopback port.  Because this method
       
  1269 	// calls itself (on the other port), we can end up trying to complete reads and writes
       
  1270 	// a couple of times.  By checking the pending flags for writes and reads, we should
       
  1271 	// avoid this extra work (even though it probably would not hurt anything).
       
  1272 	if ((attemptWrite) && (iWritePending))
       
  1273 		{
       
  1274 		TBool issueComplete = EFalse;
       
  1275 		TInt res=WriteBuf(iClientWriteBuffer,iWritePendingLength, issueComplete);
       
  1276 
       
  1277 		if (issueComplete)
       
  1278 			{
       
  1279 			WriteCompleted(res);
       
  1280 			}
       
  1281 		}
       
  1282 
       
  1283 	// Attempt to complete any reads if necessary.  See comment above writes for information
       
  1284 	// regarding the use of the pending flags.  Note that we call this on our own port.  This
       
  1285 	// is by design.  If a write was attempted, then it called the the read completion on the
       
  1286 	// other port.
       
  1287 	if ((attemptRead) && (iReadPending))
       
  1288 	{
       
  1289 		CheckSigsAndCompleteRead();
       
  1290 	}
       
  1291 
       
  1292 
       
  1293 	return KErrNone;
       
  1294 	}
       
  1295 
       
  1296 
       
  1297 
       
  1298 TInt CHWPort::SetSignalsToSpace(TUint aSignals)
       
  1299 /**
       
  1300  * This method de-asserts the signals specified by the parameter aSignals.  In addition to
       
  1301  * simply de-asserting the signals, this routine will complete any signal notification requests
       
  1302  * that are outstanding.  After handling any signal notification requests, this routine will
       
  1303  * also update the signal state of it's partner loopback port.  The other ports signals are
       
  1304  * updated only if they are considered output signals for the role that this port is playing.
       
  1305  * For example, assume that a DTE port is deasserting the RTS signal.  It determines that RTS is
       
  1306  * an output signal for a DTE port, so it must propagate the signal to the DCE by calling
       
  1307  * this routine on the DCE instance of the port.  When the DCE instance runs, it clears RTS, then
       
  1308  * determines that RTS is NOT a DCE output signal, so it does NOT attempt to propagate the signal.
       
  1309  * It is NOT an error for a DCE port to call this routine with DTE output signals.
       
  1310  * In fact, this behaviour is required in order to  * propagate signal settings from one port
       
  1311  * to the other.
       
  1312  *
       
  1313  * If signals are de-asserted, then it may be necessary to FAIL pending operations.  For example,
       
  1314  * if the port is configured to Fail if DCD is de-asserted and there is a read pending, this
       
  1315  * routine will complete the outstanding read with KErrCommsLineFail.
       
  1316  *
       
  1317  *
       
  1318  * @param	aSignals	- a bitmask specifying which signals to assert (See definition
       
  1319  *                        of KSignalDCD, KSignalCTS, etc. for bit values).
       
  1320  *
       
  1321  * @return	KErrNone
       
  1322  */
       
  1323 	{
       
  1324 	TBool completeRead = EFalse;
       
  1325 	TBool completeWrite = EFalse;
       
  1326 	TUint sigsChanged;
       
  1327 	TUint tmpSigs;
       
  1328 
       
  1329 	LOGI(_L8("SetSignalsToSpace:%04d %x \"%S\""));
       
  1330 
       
  1331 	LOGTEXT3(_L8("Loopback:SetSignalsToSpace:  Unit %d...Sigs 0x%x"), iPortName, aSignals);
       
  1332 
       
  1333 
       
  1334 	// If no signals are passed in to set, then get out of here.  This is possible when
       
  1335 	// the upper layers have used the RComm::SetSignals interface.  This interface is used
       
  1336 	// to both space and mark signals with a single call.  Frequently, this interface is used
       
  1337 	// with one of the two masks set to zero.
       
  1338 	if (!aSignals)
       
  1339 		return KErrNone;
       
  1340 
       
  1341 
       
  1342 	// iSignals is used to store the current state of the signals only, it does not
       
  1343 	// include the changed masks.  This is so that history will not be reflected.
       
  1344 	tmpSigs = iSignals;
       
  1345 	iSignals &= ~aSignals;
       
  1346 
       
  1347 	// sigsChanged contains only the signals changed by this operation, no history is contained.
       
  1348 	sigsChanged = (iSignals ^ tmpSigs);
       
  1349 
       
  1350 	// Only complete notifications if the changed sigs were specified in the mask.
       
  1351 	if (sigsChanged & iSignalMask)
       
  1352 		{
       
  1353 		// Notify people that the signals have changed.
       
  1354 		// Note that the KSignalChanged bits are stored in sigsChanged, but passed.
       
  1355 		// The tmpSigs value has the state of all the signals that they were interested in
       
  1356 		// as specified by the iSignalMask and the Changed flags.
       
  1357 		tmpSigs = (((sigsChanged & iSignalMask) * KSignalChanged) | (iSignals & iSignalMask));
       
  1358 		SignalChangeCompleted(tmpSigs, KErrNone);
       
  1359 		// Reset signal mask, another NotifiySignalChange is necessary to get any
       
  1360 		// more signal information out of the driver.
       
  1361 		iSignalMask = 0;
       
  1362 		}
       
  1363 
       
  1364 	// if I'm a DTE port and the signals changed are DTE outputs, then
       
  1365     // I've got to figure out what signals to change on the DCE side (as inputs).
       
  1366  	// else if I'm a DCE port and the signals changed are DCE outputs, then
       
  1367     // I've got to figure out what DTE signals I've got to change.
       
  1368 
       
  1369 	// The DTE Role could be ignored safely (Req7) but as long as the test
       
  1370     // harness does not ever request notification, it won't matter.  This is
       
  1371     // for potential future use.
       
  1372     if ((ECommRoleDTE == iRole) && (sigsChanged & KSignalDTEOutputs))
       
  1373 		{
       
  1374 		if (iLoopbackPort)
       
  1375 			iLoopbackPort->SetSignalsToSpace(aSignals);
       
  1376         }
       
  1377 	else if ((ECommRoleDCE == iRole) && (sigsChanged & KSignalDCEOutputs))
       
  1378 		{
       
  1379 		if (iLoopbackPort)
       
  1380 			iLoopbackPort->SetSignalsToSpace(aSignals);
       
  1381 		}
       
  1382 
       
  1383 	// if we dropped DCD, CTS, or DSR, then we need to complete any outstanding writes and
       
  1384     // reads on the DTE port if they have been configured to fail.
       
  1385 	// We only look at the DTE input signals to see if the roles, etc. change.
       
  1386 	if (ECommRoleDTE == iRole)
       
  1387 		{
       
  1388 		// DCD and DSR affect both Reads and Writes, so we'll want to complete both
       
  1389 		// reads and writes later.
       
  1390 		if (((iConfig().iHandshake & KConfigFailDCD) && (sigsChanged & KSignalDCD)) ||
       
  1391 			((iConfig().iHandshake & KConfigFailDSR) && (sigsChanged & KSignalDSR)))
       
  1392 			{
       
  1393 			completeRead = completeWrite = ETrue;
       
  1394 			}
       
  1395 
       
  1396 		// CTS has NO effect on the Reads, so don't attempt to complete any reads here.
       
  1397 		// No need to do this if we executed the above if ...
       
  1398 		else if (((iConfig().iHandshake & KConfigFailCTS) && (sigsChanged & KSignalCTS)))
       
  1399 			{
       
  1400 			completeWrite = ETrue;
       
  1401 			}
       
  1402 		}
       
  1403 	// if the DTE dropped the signals (RTS and DTR) the complete actions for the DCE
       
  1404 	// only look at the DCE input signals.
       
  1405 	else if (ECommRoleDCE == iRole)
       
  1406 		{
       
  1407 		// if DTR has changed, then we need to try to complete both reads and writes.
       
  1408 		if (((iConfig().iHandshake & KConfigFailDTR) && (sigsChanged & KSignalDTR)))
       
  1409 			{
       
  1410 			completeRead = completeWrite = ETrue;
       
  1411 			}
       
  1412 		// if RTS has changed, only attempt the Writes, RTS does not effect Reads.
       
  1413 		// No need to do this if we executed the above if ...
       
  1414 		else if (((iConfig().iHandshake & KConfigFailRTS) && (sigsChanged & KSignalRTS)))
       
  1415 			{
       
  1416 			completeWrite = ETrue;
       
  1417 			}
       
  1418 		}
       
  1419 
       
  1420 	// Note:  We don't have to work with the Obey flags when we set signals.  The obey flags
       
  1421 	// when something is set force future operations to be pended.  Operations currently pended
       
  1422 	// or already completed don't have any effect.  If any of the signals were treated as Active
       
  1423 	// Low (or Asserted means error condition) then we would have to attempt to complete
       
  1424 	// reads or writes.
       
  1425 	//
       
  1426 
       
  1427 	// if we need to complete the read and there is one pending, fail it.
       
  1428 	if ((completeRead) && (iReadPending))
       
  1429 		{
       
  1430 		ReadCompleted(KErrCommsLineFail);
       
  1431 		iReadPending = EFalse;
       
  1432 		}
       
  1433 
       
  1434 	// if we need to complete writes, do it here.
       
  1435 	if ((completeWrite) && (iWritePending))
       
  1436 		{
       
  1437 		WriteCompleted(KErrCommsLineFail);
       
  1438 		iWritePending = EFalse;
       
  1439 		}
       
  1440 
       
  1441 	return KErrNone;
       
  1442 	}
       
  1443 
       
  1444 TInt CHWPort::GetReceiveBufferLength(TInt& /* aLength */) const
       
  1445 /**
       
  1446  * This method is currently not implemented in the loopback driver.  Calling this
       
  1447  * method will return an error
       
  1448  *
       
  1449  * @param	Not Used
       
  1450  *
       
  1451  * @return	KErrNotSupported
       
  1452  */
       
  1453 	{
       
  1454 
       
  1455 	LOGI(_L8("GetReceiveBufferLength:%04d %x \"%S\""));
       
  1456 	return KErrNotSupported;
       
  1457 	}
       
  1458 
       
  1459 TInt CHWPort::SetReceiveBufferLength(TInt /* aLength */)
       
  1460 /**
       
  1461  * This method is currently not implemented in the loopback driver.  Calling this
       
  1462  * method will return an error
       
  1463  *
       
  1464  * @param	Not Used
       
  1465  *
       
  1466  * @return	KErrNotSupported
       
  1467  */
       
  1468 	{
       
  1469 	LOGI(_L8("SetReceiveBufferLength:%04d %x \"%S\""));
       
  1470 	return KErrNotSupported;
       
  1471 	}
       
  1472 
       
  1473 #ifdef _DEBUG_DEVCOMM
       
  1474 // This code will not compile given current class structure, etc.  It is left here for
       
  1475 // future reference.
       
  1476 void CHWPort::DoDumpDebugInfo(const RMessage2 &aMessage)
       
  1477 	{
       
  1478 	TCommDebugInfoPckg d;
       
  1479 	if (iRole==ECommRoleDTE)
       
  1480 		iPort.DebugInfo(d);
       
  1481 	else
       
  1482 		iPortDCE.DebugInfo(d);
       
  1483 	TRAPD(leave,aMessage.WriteL(0,d));		// trap but ignore leaves
       
  1484 	aMessage.Complete(KErrNone);
       
  1485 	}
       
  1486 #endif
       
  1487 
       
  1488 void CHWPort::Destruct()
       
  1489 /**
       
  1490  * This method is simply deletes this instance of the port, comitting sucide.
       
  1491  *
       
  1492  * @param	None
       
  1493  *
       
  1494  * @return	None
       
  1495  */
       
  1496 	{
       
  1497 	delete this;
       
  1498 	}
       
  1499 
       
  1500 
       
  1501 
       
  1502 void CHWPort::NotifySignalChange(TUint aSignalMask)
       
  1503 /**
       
  1504  * This method sets up a request to be notified when a signal change occurs on the specified
       
  1505  * signals.  Later operations will send a message to the requestor indicating the signal
       
  1506  * change.
       
  1507  *
       
  1508  * @param	aSignalMask		-	the signals that the caller is interested in monitoring.
       
  1509  *
       
  1510  * @return	None
       
  1511  */
       
  1512 	{
       
  1513 
       
  1514 	LOGTEXT3(_L8("Loopback:NotifySignalChange:  Unit %d...Mask 0x%x"), iPortName, aSignalMask);
       
  1515 
       
  1516 	iSignalMask|=aSignalMask;
       
  1517 
       
  1518 	}
       
  1519 
       
  1520 
       
  1521 void CHWPort::NotifySignalChangeCancel()
       
  1522 /**
       
  1523  * This method cancels an outstanding request to be notified when a signal change occurs.  Any
       
  1524  * outstanding signal change request will be completed with KErrCancel.
       
  1525  *
       
  1526  * @param	None
       
  1527  *
       
  1528  * @return	None
       
  1529  */
       
  1530 	{
       
  1531 
       
  1532 	LOGTEXT2(_L8("Loopback:NotifySignalChangeCancel:  Unit %d..."), iPortName);
       
  1533 
       
  1534 	if (iSignalMask != 0)
       
  1535 		{
       
  1536 		// Complete any outstanding notifications with KErrCancel
       
  1537 		SignalChangeCompleted(0, KErrCancel);
       
  1538 		iSignalMask = 0;	// set mask to zero
       
  1539 		}
       
  1540 	}
       
  1541 
       
  1542 
       
  1543 void CHWPort::NotifyConfigChange()
       
  1544 /**
       
  1545  * This method is currently not implemented in the loopback driver.
       
  1546  *
       
  1547  * @param	None
       
  1548  *
       
  1549  * @return	None
       
  1550  */
       
  1551 	{}
       
  1552 
       
  1553 void CHWPort::NotifyConfigChangeCancel()
       
  1554 /**
       
  1555  * This method is currently not implemented in the loopback driver.
       
  1556  *
       
  1557  * @param	None
       
  1558  *
       
  1559  * @return	None
       
  1560  */
       
  1561 	{}
       
  1562 
       
  1563 void CHWPort::NotifyFlowControlChange()
       
  1564 /**
       
  1565  * This method is currently not implemented in the loopback driver.
       
  1566  *
       
  1567  * @param	None
       
  1568  *
       
  1569  * @return	None
       
  1570  */
       
  1571 	{}
       
  1572 
       
  1573 void CHWPort::NotifyFlowControlChangeCancel()
       
  1574 /**
       
  1575  * This method is currently not implemented in the loopback driver.
       
  1576  *
       
  1577  * @param	None
       
  1578  *
       
  1579  * @return	None
       
  1580  */
       
  1581 	{}
       
  1582 
       
  1583 
       
  1584 void CHWPort::NotifyBreak()
       
  1585 /**
       
  1586  * This method is currently not implemented in the loopback driver.
       
  1587  *
       
  1588  * @param	None
       
  1589  *
       
  1590  * @return	None
       
  1591  */
       
  1592 	{}
       
  1593 
       
  1594 void CHWPort::NotifyBreakCancel()
       
  1595 /**
       
  1596  * This method is currently not implemented in the loopback driver.
       
  1597  *
       
  1598  * @param	None
       
  1599  *
       
  1600  * @return	None
       
  1601  */
       
  1602 	{}
       
  1603 
       
  1604 void CHWPort::NotifyDataAvailable()
       
  1605 /**
       
  1606  * Wake up when data is sent by the other side
       
  1607  *
       
  1608  * @param	None
       
  1609  *
       
  1610  * @return	None
       
  1611  */
       
  1612 	{
       
  1613 	iDataNotify=ETrue;
       
  1614 	CheckSigsAndCompleteRead();
       
  1615 	}
       
  1616 
       
  1617 void CHWPort::NotifyDataAvailableCancel()
       
  1618 /**
       
  1619  * Cancel data available notification
       
  1620  *
       
  1621  * @param	None
       
  1622  *
       
  1623  * @return	None
       
  1624  */
       
  1625 	{
       
  1626 	iDataNotify=EFalse;
       
  1627 	NotifyDataAvailableCompleted(KErrCancel);
       
  1628 	}
       
  1629 
       
  1630 void CHWPort::NotifyOutputEmpty()
       
  1631 /**
       
  1632  * This method is currently not implemented in the loopback driver.
       
  1633  *
       
  1634  * @param	None
       
  1635  *
       
  1636  * @return	None
       
  1637  */
       
  1638 	{}
       
  1639 
       
  1640 void CHWPort::NotifyOutputEmptyCancel()
       
  1641 /**
       
  1642  * This method is currently not implemented in the loopback driver.
       
  1643  *
       
  1644  * @param	None
       
  1645  *
       
  1646  * @return	None
       
  1647  */
       
  1648 	{
       
  1649 	}
       
  1650 
       
  1651 TInt CHWPort::GetFlowControlStatus(TFlowControl& /* aFlowControl */)
       
  1652 /**
       
  1653  * This method is currently not implemented in the loopback driver.
       
  1654  *
       
  1655  * @param	Not Used
       
  1656  *
       
  1657  * @return	KErrNotSupported
       
  1658  */
       
  1659 	{
       
  1660 	return KErrNotSupported;
       
  1661 	}
       
  1662 
       
  1663 TInt CHWPort::GetRole(TCommRole& aRole)
       
  1664 /**
       
  1665  * This method returns the current Role that this port is playing (ECommRoleDCE or ECommRoleDTE)
       
  1666  *
       
  1667  * @param	aRole	-	a reference to a TCommRole to return the role value in.
       
  1668  *
       
  1669  * @return	KErrNone
       
  1670  */
       
  1671 	{
       
  1672 	LOGTEXT2(_L8("Loopback:GetRole:  Unit %d..."), iPortName);
       
  1673 
       
  1674 	aRole=iRole;
       
  1675 	return KErrNone;
       
  1676 	}
       
  1677 
       
  1678 TInt CHWPort::SetRole(TCommRole aRole)
       
  1679 /**
       
  1680  * This method sets the role of the port.  Additionally, it sets the default state of the
       
  1681  * signals for this type of port.  This is the first place where signals are set as a port
       
  1682  * is opening.  The ports will assert their output signals with the exception of DCD (which
       
  1683  * is an output signal from the DCE).  DCD is left to be driven by the test harness.
       
  1684  *
       
  1685  * A test could be put into place to insure that each port is in a different role.  This was
       
  1686  * not done at this time for backwards compatibility reasons.
       
  1687  *
       
  1688  * @param	aRole	-	the TCommRole value that this port should be set to.
       
  1689  *
       
  1690  * @return	None
       
  1691  */
       
  1692 	{
       
  1693 	LOGTEXT2(_L8("Loopback:SetRole:  Unit %d..."), iPortName);
       
  1694 
       
  1695 	if (ECommRoleDTE == aRole)
       
  1696 		{
       
  1697 		SetSignalsToMark(KSignalDTR|KSignalRTS);
       
  1698 		}
       
  1699 	else // DCE
       
  1700 		{
       
  1701 		SetSignalsToMark(KSignalDSR|KSignalCTS);
       
  1702 		}
       
  1703 
       
  1704 
       
  1705 	// Informational test only.  This will produce output to the log file if both sides have the
       
  1706 	// same role set.  With both sides having the same role, none of the signal handling will
       
  1707 	// function properly.
       
  1708 #if defined (_DEBUG)
       
  1709 	if (iLoopbackPort)
       
  1710 		{
       
  1711 		TCommRole otherSide;
       
  1712 		iLoopbackPort->GetRole(otherSide);
       
  1713 		if (otherSide == aRole)
       
  1714 			LOGTEXT3(_L8("Loopback:SetRole:  Unit %d...Both sides same role %d"), iPortName, aRole);
       
  1715 		}
       
  1716 #endif
       
  1717 
       
  1718 	iRole = aRole;
       
  1719 	return KErrNone;
       
  1720 	}
       
  1721 
       
  1722 CHWPort::~CHWPort()
       
  1723 /**
       
  1724  * This method is the standard destructor for the port.  It deletes the buffer
       
  1725  * which was allocated to the port and resets the loopback port pointer to NULL.
       
  1726  *
       
  1727  * @param	None
       
  1728  *
       
  1729  * @return	None
       
  1730  */
       
  1731 	{
       
  1732 
       
  1733 
       
  1734 	delete iBuf;
       
  1735 	iBuf=NULL;
       
  1736 	iPtr.Set(NULL,0,0);
       
  1737 	if(iLoopbackPort)
       
  1738 		iLoopbackPort->SetLoopbackPort(NULL);
       
  1739 	((CHWPortFactory*)Owner())->Remove(this);
       
  1740 
       
  1741 #if defined (_DEBUG_CONSOLE_)
       
  1742 #if defined (_DEBUG_DEVCOMM)
       
  1743 	delete iDumper;
       
  1744 #endif
       
  1745 	iConsole.Close();
       
  1746 #endif
       
  1747 	}
       
  1748 
       
  1749 void CHWPort::FreeMemory()
       
  1750 /**
       
  1751  * This method is currently not implemented in the loopback driver.
       
  1752  *
       
  1753  * @param	None
       
  1754  *
       
  1755  * @return	None
       
  1756  */
       
  1757 	{}
       
  1758 
       
  1759  CPort* CHWPortFactory::NewPortL(const TUint aUnit)
       
  1760 /**
       
  1761  * This method creates a new port object.  It identifies the new object with the unit number that
       
  1762  * is supplied.  If both ports that are supported by the CHWPortFactory object have been created,
       
  1763  * then the loopback ports are initialized.
       
  1764  *
       
  1765  * @param	aUnit		-	The unit number to create.
       
  1766  *
       
  1767  * @return	CPort *		-	A pointer to the newly created object.
       
  1768  */
       
  1769 	{
       
  1770 	LOGTEXT2(_L8("Loopback:NewPortL:  Unit %d"), aUnit);
       
  1771 	if(aUnit >= (KLoopbackCount&~1))
       
  1772 		User::Leave(KErrNotSupported);
       
  1773 
       
  1774 	CPort* newPort;
       
  1775 	if (iPort[aUnit])
       
  1776 		{
       
  1777 		LOGTEXT3(_L8("Loopback:NewPortL:  Unit %d already exists! @%x"), aUnit, iPort[aUnit]);
       
  1778 		}
       
  1779 	newPort=iPort[aUnit]=CHWPort::NewL(aUnit);
       
  1780 
       
  1781 	if((iPort[aUnit])&&(PairedPort(aUnit)))
       
  1782 		{
       
  1783 		iPort[aUnit]->SetLoopbackPort(PairedPort(aUnit));
       
  1784 		PairedPort(aUnit)->SetLoopbackPort(iPort[aUnit]);
       
  1785 		}
       
  1786 	return newPort;
       
  1787 	}
       
  1788 
       
  1789 void CHWPortFactory::Info(TSerialInfo &aSerialInfo)
       
  1790 /**
       
  1791  * This method fills information into the passed structure.  It is required for factory objects.
       
  1792  *
       
  1793  * @param	aSerialInfo		-	a reference to the structure to fill in.
       
  1794  *
       
  1795  * @return	None
       
  1796  */
       
  1797 	{
       
  1798 	aSerialInfo.iDescription=SERIAL_DESCRIPTION;
       
  1799 	aSerialInfo.iName=SERIAL_NAME;
       
  1800 	aSerialInfo.iLowUnit=KCommLowUnit;
       
  1801 	aSerialInfo.iHighUnit=KLoopbackCount - 1;
       
  1802 	}
       
  1803 
       
  1804 CHWPortFactory::CHWPortFactory()
       
  1805 /**
       
  1806  * This method is the constructor for the factory object.
       
  1807  *
       
  1808  * @param	None
       
  1809  *
       
  1810  * @return	None
       
  1811  */
       
  1812 	{
       
  1813 	__DECLARE_NAME(_S("CHWPortFactory"));
       
  1814 	TName name(SERIAL_NAME);
       
  1815 	SetName(&name);
       
  1816 	iVersion=TVersion(KEC32MajorVersionNumber,KEC32MinorVersionNumber,KEC32BuildVersionNumber);
       
  1817 	}
       
  1818 
       
  1819  void CHWPortFactory::Remove(CHWPort* aPort)
       
  1820 /**
       
  1821  * This method removes an instance of the CHWPort from the factory package CHWPortFactory.
       
  1822  *
       
  1823  * @param	aPort	-	The pointer to the CHWPort pointer to be removed from the factory object.
       
  1824  *
       
  1825  * @return	None
       
  1826  *
       
  1827  * @note	If the passed in value does not match a current port, this method will panic.
       
  1828  */
       
  1829  	{
       
  1830 	LOGTEXT2(_L8("Loopback:Remove:  Port %x"), aPort);
       
  1831 	for(TUint i=0; i<KLoopbackCount; i++)
       
  1832 		{
       
  1833 		if(iPort[i]==aPort)
       
  1834 			{
       
  1835 			iPort[i]=NULL;
       
  1836 			return;
       
  1837 			}
       
  1838 		}
       
  1839 	User::Panic(_L("CHWPortFactory Panic"),0);
       
  1840 	}
       
  1841 
       
  1842 CHWPortFactory::~CHWPortFactory()
       
  1843 /**
       
  1844  * This method is the destructor for the factory object.
       
  1845  *
       
  1846  * @param	None
       
  1847  *
       
  1848  * @return	None
       
  1849  *
       
  1850  */
       
  1851 	{
       
  1852 
       
  1853 	LOGDESTROY();
       
  1854 
       
  1855 	}
       
  1856 
       
  1857 /**
       
  1858 Returns capabilities for requested port
       
  1859 */
       
  1860 TSecurityPolicy CHWPortFactory::PortPlatSecCapability(TUint /*aPort*/) const
       
  1861 	{
       
  1862 	return TSecurityPolicy(TSecurityPolicy::EAlwaysPass);
       
  1863 	}
       
  1864 
       
  1865 extern "C"
       
  1866 	{
       
  1867 	IMPORT_C CSerial * LibEntry(void);	// Force export
       
  1868 	}
       
  1869 
       
  1870 EXPORT_C CSerial * LibEntry(void)
       
  1871 /**
       
  1872  * This method is the library's main entry point.  It simply new's the factory object.
       
  1873  *
       
  1874  * @param	None
       
  1875  *
       
  1876  * @return	None
       
  1877  *
       
  1878  */
       
  1879 	{
       
  1880 
       
  1881 	return new CHWPortFactory;
       
  1882 	}
       
  1883 
       
  1884 
       
  1885 #if defined(_DEBUG_CONSOLE_)
       
  1886 // This code will not compile given current class structure, etc.  It is left here for
       
  1887 // future reference.
       
  1888 RDebugConsole::RDebugConsole()
       
  1889 	{
       
  1890 	Create();
       
  1891 	Set(_L(""),TSize(64,15));
       
  1892 
       
  1893 	}
       
  1894 
       
  1895 void RDebugConsole::Printf(TRefByValue<const TDesC> aFmt,...)
       
  1896 //
       
  1897 // Print to a console screen.
       
  1898 //
       
  1899 	{
       
  1900 
       
  1901 	VA_LIST list;
       
  1902 	VA_START(list,aFmt);
       
  1903 	TBuf<0x100> aBuf;
       
  1904 	aBuf.AppendFormatList(aFmt,list);
       
  1905 	Write(aBuf);
       
  1906 	}
       
  1907 #endif
       
  1908 
       
  1909 #if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_)
       
  1910 CCommDebugDumper* CCommDebugDumper::NewL(RDebugConsole &aConsole)
       
  1911 	{
       
  1912 	CCommDebugDumper* p=new CCommDebugDumper(aConsole);
       
  1913 	return p;
       
  1914 	}
       
  1915 
       
  1916 CCommDebugDumper::CCommDebugDumper(RDebugConsole &aConsole)
       
  1917 	:CActive(EPriorityStandard)
       
  1918 	{
       
  1919 	iRole=ECommRoleDTE;
       
  1920 	iConsole=&aConsole;
       
  1921 	CActiveScheduler::Add(this);
       
  1922 	SetActive();
       
  1923 	iConsole->Read(iKeystroke,iStatus);
       
  1924 	};
       
  1925 
       
  1926 CCommDebugDumper::~CCommDebugDumper()
       
  1927 	{
       
  1928 	Cancel();
       
  1929 	}
       
  1930 
       
  1931 void CCommDebugDumper::RunL()
       
  1932 	{
       
  1933 	TInt key=iKeystroke.Code();
       
  1934 	switch(key)
       
  1935 		{
       
  1936 		case 'd':
       
  1937 		case 'D':
       
  1938 			{
       
  1939 			TCommDebugInfoPckg d;
       
  1940 			if (iRole==ECommRoleDTE)
       
  1941 				iParent->DTEPort().DebugInfo(d);
       
  1942 			else
       
  1943 				iParent->DCEPort().DebugInfo(d);
       
  1944 			TCommDebugInfo& debug=d();
       
  1945 			iConsole->Printf(_L("rxbusy  : 0x%04x, rxHeld   : 0x%04x, \n\r"),debug.iRxBusy,debug.iRxHeld);
       
  1946 			iConsole->Printf(_L("txbusy  : 0x%04x, txHeld   : 0x%04x, \n\r"),debug.iTxBusy,debug.iTxHeld);
       
  1947 			iConsole->Printf(_L("drainRx : 0x%04x, fillTx   : 0x%04x\n\r"),debug.iDrainingRxBuf,debug.iFillingTxBuf);
       
  1948 			iConsole->Printf(_L("Txonchar: 0x%04x, TxOffchar: 0x%04x\n\r"),debug.iTxXon,debug.iTxXoff);
       
  1949 			iConsole->Printf(_L("RxonChar: 0x%04x, RxOffchar: 0x%04x\n\r"),debug.iRxXon,debug.iRxXoff);
       
  1950 			iConsole->Printf(_L("NumTX   : 0x%04x, NumRx    : 0x%04x\n\r"),debug.iTxChars,debug.iRxChars);
       
  1951 			iConsole->Printf(_L("TxLen   : 0x%04x, RxLen    : 0x%04x\n\r"),debug.iTxLength,debug.iRxLength);
       
  1952 			iConsole->Printf(_L("TxOffset: 0x%04x, RxOffset : 0x%04x\n\r"),debug.iTxOffset,debug.iRxOffset);
       
  1953 			iConsole->Printf(_L("TxInts  : 0x%04x, RxInts   : 0x%04x\n\r"),debug.iTxIntCount,debug.iRxIntCount);
       
  1954 			}
       
  1955 			break;
       
  1956 		case 's':
       
  1957 		case 'S':
       
  1958 			{
       
  1959 			TUint signals=0;
       
  1960 			if (iRole==ECommRoleDTE)
       
  1961 				signals=iParent->DTEPort().Signals();
       
  1962 			else
       
  1963 				signals=iParent->DCEPort().Signals();
       
  1964 			iConsole->Printf(_L("Signals: "));
       
  1965 			if (signals&KSignalCTS)
       
  1966 				iConsole->Printf(_L("CTS "));
       
  1967 			if (signals&KSignalDSR)
       
  1968 				iConsole->Printf(_L("DSR "));
       
  1969 			if (signals&KSignalDCD)
       
  1970 				iConsole->Printf(_L("DCD "));
       
  1971 			if (signals&KSignalRTS)
       
  1972 				iConsole->Printf(_L("RTS "));
       
  1973 			if (signals&KSignalDTR)
       
  1974 				iConsole->Printf(_L("DTR "));
       
  1975 			iConsole->Printf(_L("\n\r"));
       
  1976 			}
       
  1977 			break;
       
  1978 		default:
       
  1979 			break;
       
  1980 		}
       
  1981 
       
  1982 	SetActive();
       
  1983 	iConsole->Read(iKeystroke,iStatus);
       
  1984 	};
       
  1985 
       
  1986 void CCommDebugDumper::DoCancel()
       
  1987 	{
       
  1988 	iConsole->ReadCancel();
       
  1989 	}
       
  1990 
       
  1991 #endif