serialserver/serialportcsy/ECUART.CPP
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialserver/serialportcsy/ECUART.CPP	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,2466 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implements a complete CSY for physical serial ports
+// 
+//
+
+/**
+ @file
+*/
+
+#include <cs_port.h>
+#include <d32comm.h>
+#include <c32comm.h>
+#include <e32hal.h>
+// new header file introduced in C32 V2, old ecuart had no header file
+#include "ECUART.H"
+#include <c32comm_internal.h>
+
+// This header import is new for C32 V2 but is not configured since then we don't need to configure all
+// the logging we've added to this file during V2. The ecuartlog header file when pre-processed for pre-V2
+// will resolve all the logging to nothing since all its log macros for pre-V2 are defined empty.
+#include "ECUARTLOG.H"
+
+const TUint KCommLowUnit=0;  //< lowest port unit number for this CSY (i.e. COMM::0)
+
+#if defined(__WINS__)
+const TUint KCommHighUnit=1; //< highest port unit number for this CSY (i.e. COMM::1)
+#else // _MARM_
+const TUint KCommHighUnit=0; //< highest port unit number for this CSY (i.e. COMM::0)
+#endif
+
+const TUint KDefaultBufSize = 0x100; //< size of the Tx/Rx buffers used in CCommWriter and CCommReader
+
+_LIT(KSerialDescription, "Built in Serial ports"); //< CSY description returned by RCommServ::GetPortInfo
+#define SERIAL_NAME _S("COMM")  //< name of prefix for each com port
+
+const TInt KReaderPriority=100; //< priority for the CCommReader active object
+const TInt KWriterPriority=50;  //< priority for the CCommWriter active object
+const TInt KBreakerPriority=0;  //< priority for the CCommBreaker active object
+const TInt KNotifyPriority=0;   //< priority for CCommNotifyBase derived active objects
+
+
+//Security policy for a port.
+class TPortSecurityPolicy
+	{
+public:
+	//Port number which this policy will apply.
+	TInt iPort;
+	//Security policy.
+	TStaticSecurityPolicy iPolicy;
+	};
+
+_LIT_SECURITY_POLICY_PASS(KDefaultPortPassPolicy);
+_LIT_SECURITY_POLICY_FAIL(KPortAlwaysFailPolicy);
+
+#define KPlaceholderPortNumber -1	//a place holder port number used to initiliase KExplicitPortSecurityPolicies when no other ports require a policy different than the default.
+
+//Define policy for ports which are different from default policy (KDefaultPortPolicy) here.
+//Default policy is EAlwaysPass but to provide example ports 0-1 are explicitly set to EAlwaysPass as well.
+//Port policies must only apply for port number 0-(KMaxUnits-1).
+//Add to this array for other ports that need policing with capabilities.
+const TUint KExplicitPortPoliciesCount = 0;	//Count of the number of entries in KExplicitPortSecurityPolicies.  Currently only a place holder entry exists so the count = 0.
+const struct TPortSecurityPolicy KExplicitPortSecurityPolicies[]=
+	{
+	{KPlaceholderPortNumber, _INIT_SECURITY_POLICY_FAIL}	//this is a place holder entry which should be replaced with proper port policy when required to police a port with different capabiltiies to default policy.
+//	{0, _INIT_SECURITY_POLICY_C1( ECapabilityCommDD)},	//Example showing explicitly setting a policy different than default for Port 0
+//	{1, _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData, ECapabilityWriteUserData)}	//Example showing explicitly setting a policy different than default for Port 1
+	};
+
+
+// #define _DEBUG_CONSOLE_
+
+#if defined(_DEBUG_CONSOLE_)
+#include <e32twin.h>
+class RDebugConsole : public RConsole
+	{
+public:
+	RDebugConsole();
+public:
+	void Printf(TRefByValue<const TDesC> aFmt,...);
+	};
+
+#define DEBUG_TRACE(m) m
+
+#else	// (_DEBUG)
+
+// debug trace (disabled in Release builds)
+#define DEBUG_TRACE(m)
+//
+#endif
+
+//
+// CCommReader CCommWriter and CCommBreaker are active objects which wait on
+// completion from the serial channel for various actions.
+//
+class CHWPort;
+
+/**
+ * base class for CCommReader and CCommWriter
+ *
+ */
+class CCommReadWriteBase : public CActive
+	{
+public:
+	CCommReadWriteBase(TInt aPriority, CHWPort* aParent);
+	~CCommReadWriteBase();
+	TInt SetServerConfig(TCommServerConfig& aConfig);
+	void GetServerConfig(TCommServerConfig& aConfig) const;
+	void FreeMemory();
+	 // set the role of this port unit @param aRole new role
+	inline void SetRole(TCommRole aRole){iRole=aRole;};
+protected:
+	void SetBuffersL();
+	// return ETrue if partial buffering used
+	TBool UsePartial() {return ((iBufFlags & KCommBufferPartial)==KCommBufferPartial);}
+protected:
+	HBufC8* iBuffer;  //< pointer to the Tx/Rx buffer
+	TPtr8* iBuf;      //< pointer to a TPtr8 that points to the current buffer
+	TUint iBufFlags;  //< contains buffer flags e.g for partial read/write
+	TInt iBufSize;    //< size of the Tx/Rx buffer
+	TCommRole iRole;  //< DTE or DCE role for this port unit
+	CHWPort* iParent; //< pointer to the CHWPort object
+	};
+
+
+#if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_)
+class CCommDebugDumper : public CActive
+	{
+public:
+	static CCommDebugDumper* NewL(RDebugConsole &aConsole);
+	virtual void RunL();
+	virtual void DoCancel();
+	CCommDebugDumper::~CCommDebugDumper();
+	 // set the role of this port unit @param aRole new role
+	inline void SetRole(TCommRole aRole){iRole=aRole;};
+private:
+	CCommDebugDumper(RDebugConsole &aConsole);
+private:
+	TCommRole iRole;         //< DTE or DCE role for this port unit
+	RDebugConsole *iConsole;
+	TConsoleKey iKeystroke;
+	};
+#endif
+
+
+/**
+ * Active Comm port Reader
+ *
+ * This class is responsible for reading data from the physical
+ * comm port.
+ */
+class CCommReader : public CCommReadWriteBase
+	{
+public:
+	static CCommReader* NewL(CHWPort* aParent);
+	~CCommReader();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+	//
+	void Read(const TAny* aClientBuffer, TInt aLength);
+	void ReadCancel();
+private:
+	CCommReader(CHWPort* aParent);
+	void InitL();
+private:
+	TUint iLength;          //< number of bytes to read
+	TAny* iClientBuffer;    //< pointer to Client's buffer
+	TUint iBufPos;          //< position in Client's buffer to read into (write)
+	TUint iBufActive;       //< TRUE if partial buffering active
+	TInt iBufOneOrMoreSize; //< buffer size of ReadOneOrMore method
+	};
+
+
+/**
+ * Active Comm port Writer
+ *
+ * This class is responsible for writing data to the physical
+ * comm port.
+ */
+class CCommWriter : public CCommReadWriteBase
+	{
+public:
+	static CCommWriter* NewL(CHWPort* aParent);
+	~CCommWriter();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+	//
+	void Write(const TAny* aClientBuffer, TInt aLength);
+	void WriteCancel();
+	inline void NotificationEnable();
+	inline void NotificationDisable();
+	inline TBool IsNotificationEnabled();
+private:
+	CCommWriter(CHWPort* aParent);
+	void InitL();
+private:
+	TUint iLength;              //< number of bytes to write
+	TAny* iClientBuffer;        //< pointer to Client's buffer
+	TUint iBufPos;              //< position in Client's buffer to read from
+	TUint iBufActive;           //< TRUE if partial buffering active
+	TBool iNotificationEnabled; //< true if notification is enabled
+	};
+
+
+
+/**
+ * Active Comm port Breaker
+ *
+ * This class is responsible for handling breaks on the physical
+ * comm port.
+ */
+class CCommBreaker : public CActive
+	{
+public:
+	static CCommBreaker * NewL(CHWPort* aParent);
+	~CCommBreaker();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+	//
+	void Break(TInt aTime);
+	 // set the role of this port unit @param aRole new role
+	inline void SetRole(TCommRole aRole){iRole=aRole;};
+private:
+	CCommBreaker(CHWPort* aParent);
+private:
+	TCommRole iRole;  //< DTE or DCE role for this port unit
+	CHWPort* iParent; //< pointer to the CHWPort object
+	};
+
+
+/**
+ * Base class for Notifiers
+ *
+ */
+class CCommNotifyBase : public CActive
+	{
+public:
+	 // set the role of this port unit @param aRole new role
+	inline void SetRole(TCommRole aRole){iRole=aRole;};
+protected:
+	CCommNotifyBase(CHWPort* aParent);
+	~CCommNotifyBase();
+protected:
+	TCommRole iRole;  //< DTE or DCE role for this port unit
+	CHWPort* iParent; //< pointer to the CHWPort object
+	};
+
+
+/**
+ * This class is responsible for notifying the client when
+ * the signal control lines are changing, including breaks.
+ */
+class CCommSignalNotifier : public CCommNotifyBase
+	{
+public:
+	CCommSignalNotifier(CHWPort* aParent);
+	~CCommSignalNotifier();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+	//
+	void Start();
+	void NotifySignal(TUint aSignalMask);
+	void NotifySignalCancel();
+	void NotifyBreak();
+	void NotifyBreakCancel();
+private:
+	TUint iSignals;     //< bitmask with the new signal after notification completed
+	TUint iSignalMask;  //< bitmask with the signals to be notified
+	TInt iNotifyCount;	//< increased when either NotifySignals or NotifyBreak is using this class
+						//< decreased when RunL is called. Ensures that RComm::NotifyBreak will not
+						//< interfere with operation of RComm::NotifySignalsChange
+	};
+
+
+/**
+ * this class is responsible for notifying the client when
+ * there are some incoming data available.
+ */
+class CCommAvailableDataNotifier : public CCommNotifyBase
+	{
+public:
+	CCommAvailableDataNotifier(CHWPort* aParent);
+	~CCommAvailableDataNotifier();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+	//
+	void Start();
+	};
+
+
+/**
+ * this class is responsible for notifying the client when
+ * the flow control is changing.
+ */
+class CCommFlowControlChangeNotifier : public CCommNotifyBase
+	{
+public:
+	CCommFlowControlChangeNotifier(CHWPort* aParent);
+	~CCommFlowControlChangeNotifier();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+	//
+	void Start();
+private:
+	TFlowControl iFlowControl; //< current flow control settings
+	};
+
+
+/**
+ * this class is responsible for notifying the client when
+ * the configuration is changing.
+ */
+class CCommConfigChangeNotifier : public CCommNotifyBase
+	{
+public:
+	CCommConfigChangeNotifier(CHWPort* aParent);
+	~CCommConfigChangeNotifier();
+	void Start();
+	// from CActive
+	virtual void DoCancel();
+	virtual void RunL();
+private:
+	TCommNotificationPckg iConfig; //< current configuration package
+	};
+
+
+/**
+ * CPort is the object which interfaces to the commserver
+ */
+class CHWPort : public CPort
+	{
+public:
+	static CHWPort* NewL(TUint aUnit);
+private:
+	 CHWPort();
+public:
+	virtual void StartRead(const TAny* aClientBuffer,TInt aLength);
+	virtual void ReadCancel();
+	virtual TInt QueryReceiveBuffer(TInt& aLength) const;
+	virtual void ResetBuffers(TUint aFlags);
+	virtual void StartWrite(const TAny* aClientBuffer,TInt aLength);
+	virtual void WriteCancel();
+	virtual void Break(TInt aTime);
+	virtual void BreakCancel();
+	virtual TInt GetConfig(TDes8& aDes) const;
+	virtual TInt SetConfig(const TDesC8& aDes);
+	virtual TInt SetServerConfig(const TDesC8& aDes);
+	virtual TInt GetServerConfig(TDes8& aDes);
+	virtual TInt GetCaps(TDes8& aDes);
+	virtual TInt GetSignals(TUint& aSignals);
+	virtual TInt SetSignalsToMark(TUint aSignals);
+	virtual TInt SetSignalsToSpace(TUint aSignals);
+	virtual TInt GetReceiveBufferLength(TInt& aLength) const;
+	virtual TInt SetReceiveBufferLength(TInt aSignals);
+	virtual void Destruct();
+	virtual void FreeMemory();
+	virtual void NotifySignalChange(TUint aSignalMask);
+	virtual void NotifySignalChangeCancel();
+	virtual void NotifyConfigChange();
+	virtual void NotifyConfigChangeCancel();
+	virtual void NotifyFlowControlChange();
+	virtual void NotifyFlowControlChangeCancel();
+	virtual void NotifyBreak();
+	virtual void NotifyBreakCancel();
+	virtual void NotifyDataAvailable();
+	virtual void NotifyDataAvailableCancel();
+	virtual void NotifyOutputEmpty();
+	virtual void NotifyOutputEmptyCancel();
+	virtual TInt GetFlowControlStatus(TFlowControl& aFlowControl);
+	virtual TInt GetRole(TCommRole& aRole);
+	virtual TInt SetRole(TCommRole aRole);
+
+	virtual ~CHWPort();
+#if defined (_DEBUG_DEVCOMM)
+	virtual void DoDumpDebugInfo(const RMessage2 &aMessage);
+#endif
+	RBusDevComm& DTEPort();
+	RBusDevCommDCE& DCEPort();
+private:
+	CCommReader* iReader;                                       //< pointer to the Active Reader
+	CCommWriter* iWriter;                                       //< pointer to the Active Writer
+	CCommBreaker* iBreaker;                                     //< pointer to the Active Breaker
+	CCommSignalNotifier* iSignalNotifier;                       //< pointer to the Active Signal Notifier
+	CCommAvailableDataNotifier* iDataAvailableNotifier;         //< pointer to the Active Data available notifier
+	CCommFlowControlChangeNotifier* iFlowControlChangeNotifier; //< pointer to the Active Flow Control notifier
+	CCommConfigChangeNotifier* iConfigChangeNotifier;           //< pointer to the Active Config Change notifier
+
+	RBusDevComm iPort;           //< interface to the logical Comm port device (DTE role)
+	RBusDevCommDCE iPortDCE;     //< interface to the logical Comm port device (DCE role)
+	TCommRole iRole;             //< DTE or DCE role for this port unit
+	TUint iPortName;             //< contains the port unit number (i.e. 0 for COMM::0)
+	TBool iEarlyWriteCompletion; //< ETrue if early write completion enabled
+#if defined (_DEBUG_CONSOLE_)
+#if defined (_DEBUG_DEVCOMM)
+	CCommDebugDumper *iDumper;
+#endif
+public:
+	RDebugConsole iConsole;
+#endif
+	};
+
+
+/**
+ * "Entry point object" makes the objects which do the work
+ */
+class CHWPortFactory : public CSerial
+	{
+public:
+    CHWPortFactory();
+	virtual CPort* NewPortL(const TUint aUnit);
+	virtual void Info(TSerialInfo &aSerialInfo);
+
+public:	//from CSerial
+	TSecurityPolicy PortPlatSecCapability(TUint aPort) const;
+	};
+
+
+/**
+ * this class handles the 'Read one or more' method
+ * for ports with role DTE
+ */
+class RMaxComm : public RBusDevComm
+	{
+public:
+	static void ReadOneOrMore(RBusDevComm& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen);
+	};
+
+
+void RMaxComm::ReadOneOrMore(RBusDevComm& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen)
+/**
+ * reads one or more bytes from the physical DTE com port
+ *
+ * @param aComm   handle to the logical com port device
+ * @param aStatus handle for asyncronous communications
+ * @param aDes    buffer to be read into
+ * @param aLen    max number of bytes to read
+ */
+    {
+	LOGECUART2(_L8("RMaxComm::ReadOneOrMore(), (max. bytes to read) aLen = %d"), aLen);
+	RMaxComm& r = (RMaxComm&)aComm;
+	aLen = -aLen; // Note: negative length here means ReadOneOrMore
+	              //       see RComm::ReadOneOrMore in CC_CLI.CPP
+	r.DoRequest(ERequestRead, aStatus, &aDes, &aLen);
+    }
+
+
+/**
+ * this class handles the 'Read one or more' method
+ * for ports with role DCE
+ */
+class RMaxCommDCE : public RBusDevCommDCE
+	{
+public:
+	static void ReadOneOrMore(RBusDevCommDCE& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen);
+	};
+
+
+void RMaxCommDCE::ReadOneOrMore(RBusDevCommDCE& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen)
+/**
+ * reads one or more bytes from the physical DCE com port
+ *
+ * @param aComm   handle to the logical com port device
+ * @param aStatus handle for asyncronous communications
+ * @param aDes    buffer to be read into
+ * @param aLen    max number of bytes to read
+ */
+    {
+	LOGECUART2(_L8("RMaxCommDCE::ReadOneOrMore(), (max. bytes to read) aLen = %d"), aLen);
+	RMaxCommDCE& r = (RMaxCommDCE&)aComm;
+	aLen = -aLen; // Note: negative length here means ReadOneOrMore
+	              //       see RComm::ReadOneOrMore in CC_CLI.CPP
+	r.DoRequest(ERequestRead, aStatus, &aDes, &aLen);
+    }
+
+
+
+
+void Fault(TCommFault aFault)
+/**
+ * Panic the comm module (us)
+ *
+ * @param aFault Panic code
+ */
+	{
+	LOGECUART3(_L8("Fault(), (TCommFault) aFault = %d (%S)"), aFault, &TECUARTLOG::CommFaultStr(aFault));
+	_LIT(KCsyPanicCategory, "CHWComm" );
+	User::Panic(KCsyPanicCategory, aFault);
+	}
+
+
+//
+// implementation of CCommReadWriteBase
+//
+
+
+CCommReadWriteBase::CCommReadWriteBase(TInt aPriority, CHWPort* aParent)
+/**
+ * C'tor
+ *
+ * @param aPriority priority of the Active Object
+ * @param aParent   pointer to the owner, the CHWPort object
+ */
+	:CActive(aPriority)
+	,iBufSize(KDefaultBufSize)
+	,iRole(ECommRoleDTE)
+	,iParent(aParent)
+	{
+	LOGECUART1(_L8("CCommReadWriteBase::CCommReadWriteBase()"));
+	}
+
+
+CCommReadWriteBase::~CCommReadWriteBase()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommReadWriteBase::~CCommReadWriteBase()"));
+	delete iBuffer;
+	delete iBuf;
+	}
+
+
+TInt CCommReadWriteBase::SetServerConfig(TCommServerConfig& aConfig)
+/**
+ * Set the port to use partial reads/writes or the bungee buffer
+ *
+ * @param aConfig new Comm server configurations
+ * @return TInt error code. KErrNone for sucess
+ */
+	{
+	LOGECUART1(_L8("CCommReadWriteBase::SetServerConfig()"));
+	TCommServerConfigV01& c = aConfig();
+	TInt res = KErrNone;
+	if (c.iBufFlags & KCommBufferPartial)
+		{
+		TInt bufSave = iBufSize;
+		iBufSize = c.iBufSize;
+		TRAP(res, SetBuffersL();)
+		if (res==KErrNone)
+			iBufFlags = c.iBufFlags;
+		else
+			iBufSize = bufSave;
+		}
+	return res;
+	}
+
+
+void CCommReadWriteBase::GetServerConfig(TCommServerConfig& aConfig) const
+/**
+ * read the comm server buffer config from the reader
+ *
+ * @param aConfig reference to Comm server configurations to be changed
+ */
+	{
+	LOGECUART1(_L8("CCommReadWriteBase::GetServerConfig()"));
+	aConfig().iBufFlags = iBufFlags;
+	aConfig().iBufSize = iBufSize;
+	}
+
+
+void CCommReadWriteBase::FreeMemory()
+/**
+ * Reduce allocation levels by order of the comm server
+ */
+	{
+	LOGECUART1(_L8("CCommReadWriteBase::FreeMemory()"));
+	TRAP_IGNORE(SetBuffersL());
+	}
+
+
+void CCommReadWriteBase::SetBuffersL()
+/**
+ * Attempt to free up some memory
+ *
+ * @leave This function may leave in case of OOM
+ */
+	{
+	LOGECUART1(_L8("CCommReadWriteBase::SetBuffersL()"));
+	if (!IsActive())
+		{
+		TInt allocLen = Align4(iBufSize);
+		delete iBuffer;
+		delete iBuf;
+		iBuf = NULL;   // set to NULL, in case new leaves
+		iBuffer = NULL;
+		iBuffer = HBufC8::NewMaxL(allocLen);
+		iBuf = new (ELeave) TPtr8((TText8*)iBuffer->Des().Ptr(), allocLen, allocLen);
+		}
+	}
+
+
+//
+// implementation of CCommReader
+//
+
+
+CCommReader* CCommReader::NewL(CHWPort* aParent)
+/**
+ * static function, create and init a comm reader active object
+ *
+ * @param aParent pointer to the CHWPort object
+ * @return a newly created CCommReader object
+ */
+	{
+	LOGECUART1(_L8("CCommReader::NewL()"));
+	CCommReader* c = new (ELeave) CCommReader(aParent);
+	CleanupStack::PushL(c);
+	c->InitL();
+	CleanupStack::Pop();
+	CActiveScheduler::Add(c);
+	return c;
+	}
+
+
+CCommReader::~CCommReader()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommReader::~CCommReader()"));
+	Cancel();
+	}
+
+
+void CCommReader::DoCancel()
+/**
+ * Cancel an outstanding request
+ */
+	{
+	LOGECUART1(_L8("CCommReader::DoCancel()"));
+	__ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding));
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().ReadCancel();
+	else
+		iParent->DCEPort().ReadCancel();
+	}
+
+
+void CCommReader::RunL()
+/**
+ * Read request has completed
+ */
+	{
+	LOGECUART2(_L8("CCommReader::RunL(), iStatus = %d"), iStatus.Int());
+	DEBUG_TRACE((iParent->iConsole.Printf(_L("CCommReader::RunL\n\r"))));
+
+	TInt len = iLength;
+
+	DEBUG_TRACE((iParent->iConsole.Printf(_L("Write %x bytes to 0x%x+%x\n\r"),iBuf->Size(),iPendingRead.Ptr0(),iBufPos)));
+	iParent->IPCWrite(iClientBuffer,*iBuf, iBufPos);
+
+	if (iBufActive)
+		{
+		iBufPos+=iBufSize;
+		TInt left;
+
+		if (iBufOneOrMoreSize)
+			{
+			//
+			//	We are in ReadOneOrMore HELL
+			//
+			left=iBufOneOrMoreSize-iBufPos;
+			if (left<iBufSize)
+				{
+				len=left;
+				iBufActive=EFalse;
+				}
+			else
+				len=iBufSize;
+			}
+		else
+			{
+			left=len-iBufPos;
+			if (left<iBufSize)
+				{
+				len=left;
+				iBufActive=EFalse;
+				}
+			else
+				len=iBufSize;
+			}
+		//
+		//	Next block
+		//
+		iBuf->SetLength(0);
+
+		LOGECUART2(_L8("Read %d bytes from serial"), len);
+		DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len)));
+		if (iRole==ECommRoleDTE)
+			iParent->DTEPort().Read(iStatus,*iBuf,len);
+		else
+			iParent->DCEPort().Read(iStatus,*iBuf,len);;
+		SetActive();
+		return;
+		}
+	LOGECUART1(_L8("Read Completed"));
+	DEBUG_TRACE((iParent->iConsole.Write(_L("readCompleted \n\r"))));
+
+	iParent->ReadCompleted(iStatus.Int());
+	}
+
+
+
+void CCommReader::Read(const TAny* aClientBuffer, TInt aLength)
+/**
+ * resize the buffer and queue a read
+ *
+ * @param aClientBuffer pointer to the Client's buffer
+ * @param aLength number of bytes to read
+ */
+	{
+	LOGECUART2(_L8("CCommReader::Read(), aLength (number of Bytes to read) = %d"), aLength);
+	iClientBuffer=(TAny*)aClientBuffer;
+	iLength=aLength;
+	TInt& len=aLength;
+	if (len==0)
+		{
+		iParent->ReadCompleted(KErrNone);
+		return;
+		}
+
+	TBool doOneOrMore=EFalse;
+	if (len<0)
+		{
+		doOneOrMore=ETrue;
+		len=-len;
+		}
+
+
+	if ((UsePartial() && len>iBufSize) || (UsePartial()==EFalse && len>iBuf->MaxLength()))
+		{
+		if (UsePartial()==EFalse)
+			{
+			TInt allocLen=Align4(len);
+
+			TRAPD(res, iBuffer=iBuffer->ReAllocL(allocLen));
+			if(res != KErrNone)
+				{
+				delete iBuffer;
+				iBuffer=NULL;
+				LOGECUART1(_L8("Read Completed"));
+				DEBUG_TRACE((iParent->iConsole.Write(_L("readCompleted \n\r"))));
+				iParent->ReadCompleted(res);
+				return;
+				}
+
+			delete iBuf;
+			iBuf=NULL;
+			iBuf=new TPtr8((TText8*)iBuffer->Des().Ptr(), allocLen, allocLen);
+			if (iBuf == NULL)
+				{
+				iParent->ReadCompleted(KErrNoMemory);
+				return;
+				}
+			}
+		else
+			{
+			iBufActive=ETrue;
+			iBufPos=0;
+			len=iBufSize;
+			}
+		}
+
+
+	iBuf->SetLength(0);
+	if (iBufActive)
+		{
+		if (doOneOrMore)
+			{
+			if (iRole==ECommRoleDTE)
+				{
+				RBusDevComm port = iParent->DTEPort();
+				iBufOneOrMoreSize = port.QueryReceiveBuffer();
+				if (iBufOneOrMoreSize < iBuffer->Length())
+					{
+					RMaxComm::ReadOneOrMore(port, iStatus, *iBuf, len);
+					iBufActive = EFalse; // Not needed
+					}
+				else
+					{
+					//	Just do normal reads on it
+					LOGECUART2(_L8("Read %d bytes from serial"), len);
+					DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len)));
+					port.Read(iStatus,*iBuf,len);
+					}
+				}
+			else
+				{
+				RBusDevCommDCE port = iParent->DCEPort();
+				iBufOneOrMoreSize=port.QueryReceiveBuffer();
+				if (iBufOneOrMoreSize<iBuffer->Length())
+					{
+					RMaxCommDCE::ReadOneOrMore(port,iStatus,*iBuf,len);
+					iBufActive=EFalse; // Not needed
+					}
+				else
+					{
+					//	Just do normal reads on it
+					LOGECUART2(_L8("Read %d bytes from serial"), len);
+					DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len)));
+					port.Read(iStatus,*iBuf,len);
+					}
+				}
+			}
+		else
+			{
+			LOGECUART2(_L8("Read %d bytes from serial"), len);
+			DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len)));
+			if (iRole==ECommRoleDTE)
+				iParent->DTEPort().Read(iStatus,*iBuf,len);
+			else
+				iParent->DCEPort().Read(iStatus,*iBuf,len);
+			}
+		}
+	else
+		{
+		if (iRole==ECommRoleDTE)
+			{
+			RBusDevComm port = iParent->DTEPort();
+			if (doOneOrMore)
+				RMaxComm::ReadOneOrMore(port,iStatus,*iBuf,len);
+			else
+				{
+				LOGECUART2(_L8("Read %d bytes from serial"), len);
+				DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len)));
+				port.Read(iStatus,*iBuf,len);
+				}
+			}
+		else
+			{
+			RBusDevCommDCE port = iParent->DCEPort();
+			if (doOneOrMore)
+				RMaxCommDCE::ReadOneOrMore(port,iStatus,*iBuf,len);
+			else
+				{
+				LOGECUART2(_L8("Read %d bytes from serial"), len);
+				DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len)));
+				port.Read(iStatus,*iBuf,len);
+				}
+			}
+		}
+
+	SetActive();
+	}
+
+
+void CCommReader::ReadCancel()
+/**
+ * Cancel a read
+ */
+	{
+	LOGECUART1(_L8("CCommReader::ReadCancel()"));
+	if(IsActive())
+		{
+		Cancel();
+		if(iBuf->Length()) // Copy any data to client
+			iParent->IPCWrite(iClientBuffer, *iBuf, iBufPos); // todo check return value ?
+		}
+	}
+
+
+CCommReader::CCommReader(CHWPort* aParent)
+/**
+ * C'tor - pass priority up to CActive
+ */
+	:CCommReadWriteBase(KReaderPriority, aParent)
+	{
+	}
+
+
+void CCommReader::InitL()
+/**
+ * Allocate buffers
+ */
+	{
+	SetBuffersL();
+	}
+
+
+//
+// implementation of CCommWriter
+//
+
+
+CCommWriter* CCommWriter::NewL(CHWPort* aParent)
+/**
+ * static function, create and init a comm writer active object
+ *
+ * @param aParent pointer to the CHWPort object
+ * @return a newly created CCommWriter object
+ */
+	{
+	LOGECUART1(_L8("CCommWriter::NewL()"));
+	CCommWriter* c = new (ELeave) CCommWriter(aParent);
+	CleanupStack::PushL(c);
+	c->InitL();
+	CleanupStack::Pop();
+	CActiveScheduler::Add(c);
+	return c;
+	}
+
+
+CCommWriter::~CCommWriter()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommWriter::~CCommWriter()"));
+	Cancel();
+	}
+
+
+void CCommWriter::DoCancel()
+/**
+ * Cancel a pending write
+ */
+	{
+	LOGECUART1(_L8("CCommWriter::DoCancel()"));
+	__ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding));
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().WriteCancel();
+	else
+		iParent->DCEPort().WriteCancel();
+	}
+
+
+void CCommWriter::RunL()
+/**
+ * a write has completed
+ */
+	{
+	LOGECUART2(_L8("CCommWriter::RunL(), iStatus = %d"), iStatus.Int());
+	DEBUG_TRACE((iParent->iConsole.Write(_L("CCommWriter::RunL\n\r"))));
+	if (iBufActive)
+		{
+		//
+		//	Did the last chunk get through OK ?
+		//
+		if (iStatus.Int() != KErrNone)
+			{
+			iBufActive=EFalse;
+			iBufPos=0;
+			iParent->WriteCompleted(iStatus.Int());
+			return;
+			}
+
+		TInt len=iLength;
+		TInt left=len-iBufPos;
+		//
+		//	Read the next chunk into our buffer
+		//
+		DEBUG_TRACE((iParent->iConsole.Printf(_L("Read %x bytes from 0x%x+%x\n\r"),iBuf->Size(),iPendingWrite.Ptr0(),iBufPos)));
+		TInt res;
+		if((res=iParent->IPCRead(iClientBuffer,*iBuf, iBufPos))!=KErrNone)
+			{
+			iParent->WriteCompleted(res);
+			return;
+			}
+		//
+		//	Still need buffering ?
+		//
+		if (left<iBufSize)
+			{
+			iBufActive=EFalse;
+			iBufPos=0;
+			len=left;
+			}
+		else
+			{
+			iBufPos+=iBufSize;
+			len=iBufSize;
+			}
+		iBuf->SetLength(len);
+		LOGECUART2(_L8("Write %x bytes to serial"), len);
+		DEBUG_TRACE((iParent->iConsole.Printf(_L("Write %x bytes to serial\n\r"),len)));
+		if (iRole==ECommRoleDTE)
+			iParent->DTEPort().Write(iStatus,*iBuf,len);
+		else
+			iParent->DCEPort().Write(iStatus,*iBuf,len);
+		SetActive();
+		return;
+		}
+	LOGECUART1(_L8("Write Completed"));
+	DEBUG_TRACE((iParent->iConsole.Write(_L("writeCompleted \n\r"))));
+
+	if (iNotificationEnabled)
+		{
+		iParent->NotifyOutputEmptyCompleted(iStatus.Int());
+		iNotificationEnabled=EFalse;
+		}
+	iParent->WriteCompleted(iStatus.Int());
+	}
+
+
+void CCommWriter::Write(const TAny* aClientBuffer, TInt aLength)
+/**
+ * resize the buffer and queue a write
+ *
+ * @param aClientBuffer pointer to the Client's buffer
+ * @param aLength number of bytes to write
+ */
+	{
+	LOGECUART2(_L8("CCommWriter::Write(), aLength = %d"), aLength);
+	iClientBuffer = (TAny*)aClientBuffer;
+	iLength = aLength;
+
+	TInt& len = aLength;
+	if (len==0)
+		{
+		if (iRole==ECommRoleDTE)
+			iParent->DTEPort().Write(iStatus, TPtrC8(NULL,0));
+		else
+			iParent->DCEPort().Write(iStatus, TPtrC8(NULL,0));
+		}
+	else
+		{
+		if ((UsePartial() && len>iBufSize) || (UsePartial()==EFalse && len>iBuf->MaxLength()))
+			{
+			if (UsePartial()==EFalse)
+				{
+				TInt allocLen=Align4(len);
+
+				TRAPD(res, iBuffer=iBuffer->ReAllocL(allocLen));
+				if(res!=KErrNone)
+					{
+					delete iBuffer;
+					iBuffer=NULL;
+					iParent->WriteCompleted(res);
+					return;
+					}
+
+				delete iBuf;
+				iBuf=NULL;
+				iBuf = new TPtr8((TText8*)iBuffer->Des().Ptr(), allocLen, allocLen);
+				if (iBuf == NULL)
+					{
+					iParent->WriteCompleted(KErrNoMemory);
+					return;
+					}
+				}
+			else
+				{
+				iBufActive=ETrue;
+				len=iBufSize;
+				iBufPos=len;
+				}
+			}
+
+		iBuf->SetLength(len);
+		LOGECUART4(_L8("Read %d bytes from 0x%x+%x"), iBuf->Size(), aClientBuffer, iBufPos);
+		DEBUG_TRACE((iParent->iConsole.Printf(_L("Read %x bytes from 0x%x+%x\n\r"),iBuf->Size(),aClientBuffer,iBufPos)));
+		TInt res;
+		if((res=iParent->IPCRead(aClientBuffer,*iBuf))!=KErrNone)
+			{
+			iParent->WriteCompleted(res);
+			return;
+			}
+		LOGECUART2(_L8("Write %x bytes to serial"), len);
+		DEBUG_TRACE((iParent->iConsole.Printf(_L("Write %x bytes to serial\n\r"),len)));
+
+		if (iRole==ECommRoleDTE)
+			iParent->DTEPort().Write(iStatus, *iBuf, len);
+		else
+			iParent->DCEPort().Write(iStatus, *iBuf, len);
+		}
+
+	SetActive();
+	}
+
+
+void CCommWriter::WriteCancel()
+/**
+ * Cancel a write
+ */
+	{
+	LOGECUART1(_L8("CCommWriter::WriteCancel()"));
+	Cancel();
+	}
+
+
+void CCommWriter::NotificationEnable()
+/**
+ * enables notification when output buffer is empty.
+ * activated when a clients calls RComm::NotifyOutputEmpty
+ */
+	{
+	LOGECUART1(_L8("CCommWriter::NotificationEnable()"));
+	iNotificationEnabled = ETrue;
+	}
+
+
+void CCommWriter::NotificationDisable()
+/**
+ * disables notification when output buffer is empty
+ * deactivated when a clients calls RComm::NotifyOutputEmptyCancel
+ */
+	{
+	LOGECUART1(_L8("CCommWriter::NotificationDisable()"));
+	iNotificationEnabled = EFalse;
+	}
+
+
+TBool CCommWriter::IsNotificationEnabled()
+/**
+ * returns ETrue if notification on output buffer empty is enabled
+ */
+	{
+	LOGECUART2(_L8("CCommWriter::IsNotificationEnabled(), iNotificationEnabled = %d"), iNotificationEnabled);
+	return iNotificationEnabled;
+	}
+
+
+CCommWriter::CCommWriter(CHWPort* aParent)
+/**
+ * C'Tor
+ */
+	:CCommReadWriteBase(KWriterPriority, aParent)
+	{
+	}
+
+
+void CCommWriter::InitL()
+/**
+ * Allocate buffers
+ */
+	{
+	SetBuffersL();
+	}
+
+
+//
+// implementation of CCommBreaker
+//
+
+
+CCommBreaker* CCommBreaker::NewL(CHWPort* aParent)
+/**
+ * static function, create a comm breaker object
+ *
+ * @param aParent pointer to the CHWPort object
+ * @return a newly created CCommBreaker object
+ */
+	{
+	LOGECUART1(_L8("CCommBreaker::NewL()"));
+	CCommBreaker* c = new (ELeave) CCommBreaker(aParent);
+	CActiveScheduler::Add(c);
+	return c;
+	}
+
+
+CCommBreaker::~CCommBreaker()
+/**
+ * D'Tor
+ */
+	{
+	LOGECUART1(_L8("CCommBreaker::~CCommBreaker()"));
+	Cancel();
+	}
+
+
+void CCommBreaker::DoCancel()
+/**
+ * Cancel a pending break.
+ */
+	{
+	LOGECUART1(_L8("CCommBreaker::DoCancel()"));
+	__ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding));
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().BreakCancel();
+	else
+		iParent->DCEPort().BreakCancel();
+	}
+
+
+void CCommBreaker::RunL()
+/**
+ * a break has completed. forward the news to the parent
+ */
+	{
+	TInt status = iStatus.Int();
+	LOGECUART2(_L8("CCommBreaker::RunL(), iStatus = %d"), status);
+	iParent->BreakCompleted(status);
+	}
+
+
+void CCommBreaker::Break(TInt aTime)
+/**
+ * Queue a break operation
+ *
+ * @param aTime Length of break in micro seconds
+ */
+	{
+	LOGECUART2(_L8("CCommBreaker::Break(), aTime (length of break in micro secs) = %d"), aTime);
+	if (aTime==0)
+		{
+		iParent->BreakCompleted(KErrNone);
+		}
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().Break(iStatus, aTime);
+	else
+		iParent->DCEPort().Break(iStatus, aTime);
+	SetActive();
+	}
+
+
+CCommBreaker::CCommBreaker(CHWPort* aParent)
+/**
+ * C'Tor
+ *
+ * @param aParent pointer to the CHWPort object
+ */
+	:CActive(KBreakerPriority)
+	,iRole(ECommRoleDTE)
+	,iParent(aParent)
+	{
+	}
+
+
+//
+// implementation of CCommNotifyBase
+//
+
+
+CCommNotifyBase::CCommNotifyBase(CHWPort* aParent)
+/**
+ * C'tor
+ *
+ * @param aParent pointer to the CHWPort object
+ */
+	:CActive(KNotifyPriority)
+	,iRole(ECommRoleDTE)
+	,iParent(aParent)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+CCommNotifyBase::~CCommNotifyBase()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommNotifyBase::~CCommNotifyBase()"));
+	}
+
+
+//
+// implementation of CCommSignalNotifier
+//
+
+
+CCommSignalNotifier::CCommSignalNotifier(CHWPort* aParent)
+/**
+ * C'tor
+ *
+ * @param aParent pointer to the CHWPort object
+ */
+	:CCommNotifyBase(aParent)
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::CCommSignalNotifier()"));
+	}
+
+
+CCommSignalNotifier::~CCommSignalNotifier()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::~CCommSignalNotifier()"));
+	}
+
+
+void CCommSignalNotifier::DoCancel()
+/**
+ * Cancel a pending notification.
+ */
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::DoCancel()"));
+	__ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding));
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().NotifySignalChangeCancel();
+	else
+		iParent->DCEPort().NotifySignalChangeCancel();
+	}
+
+
+void CCommSignalNotifier::RunL()
+/**
+ * a notification has completed
+ */
+	{
+	LOGECUART2(_L8("CCommSignalNotifier::RunL(), iStatus = %d"), iStatus.Int());
+	if (iStatus.Int())
+		{
+		iParent->SignalChangeCompleted(iSignals,iStatus.Int());
+		iParent->BreakNotifyCompleted(iStatus.Int());
+		iSignalMask = 0;
+		iNotifyCount = 0;
+		return;
+		}
+
+	if (iSignals & ((KSignalDTEOutputs|KSignalDTEInputs)*KSignalChanged))	// these don't include BREAK
+		{
+		iNotifyCount--;
+		iParent->SignalChangeCompleted(iSignals,iStatus.Int());
+		iSignalMask &= (KSignalBreak);	// mask out everything but the BREAK signal
+		}
+	if (iSignals & KBreakChanged)
+		{
+		iNotifyCount--;
+		iParent->BreakNotifyCompleted(iStatus.Int());
+		iSignalMask&=(~KSignalBreak);
+		}
+	__ASSERT_ALWAYS(iNotifyCount>=0, Fault(ENegativeCount));
+	if (iNotifyCount>0)
+		Start();
+	}
+
+void CCommSignalNotifier::Start()
+/**
+ * start the notification
+ */
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::Start()"));
+	if (IsActive())
+		Cancel();
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().NotifySignalChange(iStatus, iSignals, iSignalMask);
+	else
+		iParent->DCEPort().NotifySignalChange(iStatus, iSignals, iSignalMask);
+	SetActive();
+	}
+
+
+void CCommSignalNotifier::NotifySignal(TUint aSignalMask)
+/**
+ * notify client when signal changes
+ *
+ * @param aSignalMask bitmask with the signals to be notified on
+ */
+	{
+	LOGECUART2(_L8("CCommSignalNotifier::NotifySignal(), aSignalMask = %d"), aSignalMask);
+	TUint reqSigs = aSignalMask & ~KSignalBreak;
+	if (!reqSigs)
+		{// User has only asked to be notified of break.
+		iParent->SignalChangeCompleted(iSignals, KErrArgument);
+		return;
+		}
+	iNotifyCount++;
+	iSignalMask |= reqSigs;
+	Start();
+	}
+
+
+void CCommSignalNotifier::NotifySignalCancel()
+/**
+ * cancel an outstanding signal change notification
+ */
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::NotifySignalCancel()"));
+	Cancel();
+	iSignalMask &= (KSignalBreak);	// set mask to zero, excluding BREAK
+	if (--iNotifyCount>0)	// NotifyBreak may still be outstanding
+		Start();
+	}
+
+
+void CCommSignalNotifier::NotifyBreak()
+/**
+ * notify client if break occurs
+ */
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::NotifyBreak()"));
+	iNotifyCount++;
+	iSignalMask |= KSignalBreak;
+	Start();
+	}
+
+
+void CCommSignalNotifier::NotifyBreakCancel()
+/**
+ * cancel an outstanding break notification
+ */
+	{
+	LOGECUART1(_L8("CCommSignalNotifier::NotifyBreakCancel()"));
+	Cancel();
+	iSignalMask &= (~KSignalBreak);	// mask out the BREAK signal
+	if (--iNotifyCount>0)					// NotifySignals may still be outstanding
+		Start();
+	}
+
+
+//
+// implementation of CCommAvailableDataNotifier
+//
+
+
+CCommAvailableDataNotifier::CCommAvailableDataNotifier(CHWPort* aParent)
+/**
+ * C'tor
+ *
+ * @param aParent pointer to the CHWPort object
+ */
+	:CCommNotifyBase(aParent)
+	{
+	}
+
+
+CCommAvailableDataNotifier::~CCommAvailableDataNotifier()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommAvailableDataNotifier::~CCommAvailableDataNotifier()"));
+	}
+
+
+void CCommAvailableDataNotifier::DoCancel()
+/**
+ * Cancel a pending data available notification.
+ */
+	{
+	__ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding));
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().NotifyReceiveDataAvailableCancel();
+	else
+		iParent->DCEPort().NotifyReceiveDataAvailableCancel();
+	}
+
+
+void CCommAvailableDataNotifier::RunL()
+/**
+ * the notification has completed, and data is available
+ */
+	{
+	LOGECUART2(_L8("CCommAvailableDataNotifier::RunL(), iStatus = %d"), iStatus.Int());
+	iParent->NotifyDataAvailableCompleted(iStatus.Int());
+	}
+
+
+void CCommAvailableDataNotifier::Start()
+/**
+ * start notification on data available
+ */
+	{
+	LOGECUART1(_L8("CCommAvailableDataNotifier::Start()"));
+	if (iRole==ECommRoleDTE)
+		iParent->DTEPort().NotifyReceiveDataAvailable(iStatus);
+	else
+		iParent->DCEPort().NotifyReceiveDataAvailable(iStatus);
+	SetActive();
+	}
+
+
+//
+// implementation of CCommFlowControlChangeNotifier
+//
+
+
+CCommFlowControlChangeNotifier::CCommFlowControlChangeNotifier(CHWPort* aParent)
+/**
+ * C'tor
+ *
+ * @param aParent pointer to the CHWPort object
+ */
+	:CCommNotifyBase(aParent)
+	{
+	}
+
+
+CCommFlowControlChangeNotifier::~CCommFlowControlChangeNotifier()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommFlowControlChangeNotifier::~CCommFlowControlChangeNotifier()"));
+	}
+
+
+void CCommFlowControlChangeNotifier::DoCancel()
+/**
+ * Cancel a pending flow control change notification.
+ */
+	{
+	LOGECUART1(_L8("CCommFlowControlChangeNotifier::DoCancel()"));
+	__ASSERT_ALWAYS(iRole==ECommRoleDCE,Fault(EWrongRole));
+	__ASSERT_ALWAYS(IsActive(),Fault(ECancelNotOutstanding));
+	iParent->DCEPort().NotifyFlowControlChangeCancel();
+	}
+
+
+void CCommFlowControlChangeNotifier::RunL()
+/**
+ *	The device driver does not give the new value of flow control status when the notification
+ *	completes so we go and ask for it. If this impedes performance, it may be worth taking the
+ *  plunge and working out the value ourselves - it should just be the opposite (ON/OFF) each time
+ *  it completes.
+ */
+	{
+	LOGECUART2(_L8("CCommFlowControlChangeNotifier::RunL(), iStatus = %d"), iStatus.Int());
+	__ASSERT_ALWAYS(iRole==ECommRoleDCE, Fault(EWrongRole));
+	iParent->DCEPort().GetFlowControlStatus(iFlowControl);
+	iParent->FlowControlChangeCompleted(iFlowControl,iStatus.Int());
+	}
+
+
+void CCommFlowControlChangeNotifier::Start()
+/**
+ * start notification on flow control change
+ *
+ * @note Only supported for DCE role
+ */
+	{
+	LOGECUART1(_L8("CCommFlowControlChangeNotifier::Start()"));
+	if (iRole==ECommRoleDTE)
+		iParent->FlowControlChangeCompleted(iFlowControl, KErrNotSupported);
+	else
+		{
+		iParent->DCEPort().NotifyFlowControlChange(iStatus);
+		SetActive();
+		}
+	}
+
+
+//
+// implementation of CCommConfigChangeNotifier
+//
+
+
+CCommConfigChangeNotifier::CCommConfigChangeNotifier(CHWPort* aParent)
+/**
+ * C'tor
+ *
+ * @param aParent pointer to the CHWPort object
+ */
+	:CCommNotifyBase(aParent)
+	{
+	LOGECUART1(_L8("CCommConfigChangeNotifier::CCommConfigChangeNotifier()"));
+	}
+
+
+CCommConfigChangeNotifier::~CCommConfigChangeNotifier()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CCommConfigChangeNotifier::~CCommConfigChangeNotifier()"));
+	}
+
+
+void CCommConfigChangeNotifier::Start()
+/**
+ * start notification on config change
+ *
+ * @note Only supported for DCE role
+ */
+	{
+	LOGECUART1(_L8("CCommConfigChangeNotifier::Start()"));
+	if (iRole==ECommRoleDTE)
+		iParent->ConfigChangeCompleted(iConfig, KErrNotSupported);
+	else
+		{
+		iParent->DCEPort().NotifyConfigChange(iStatus, iConfig);
+		SetActive();
+		}
+	}
+
+
+void CCommConfigChangeNotifier::DoCancel()
+/**
+ * Cancel a pending config change notification.
+ */
+	{
+	LOGECUART1(_L8("CCommConfigChangeNotifier::DoCancel()"));
+	__ASSERT_ALWAYS(iRole==ECommRoleDCE,Fault(EWrongRole));
+	__ASSERT_ALWAYS(IsActive(),Fault(ECancelNotOutstanding));
+	iParent->DCEPort().NotifyConfigChangeCancel();
+	}
+
+
+void CCommConfigChangeNotifier::RunL()
+/**
+ * the config change notification has completed,
+ * forward the news to the client.
+ */
+	{
+	LOGECUART2(_L8("CCommConfigChangeNotifier::RunL(), iStatus = %d"), iStatus.Int());
+	iParent->ConfigChangeCompleted(iConfig, iStatus.Int());
+	}
+
+
+void CloseObject(TAny* aObject)
+/**
+ * Close an object from the cleanup stack
+ *
+ * @param aObject pointer to the object to close
+ */
+	{
+	LOGECUART1(_L8("CloseObject()"));
+	((CObject*)aObject)->Close();
+	}
+
+
+//
+// implementation of CHWPort
+//
+
+
+CHWPort* CHWPort::NewL(TUint aUnit)
+/**
+ * Make a new CPort for the comm server
+ *
+ * @param aUnit unit number of comm port (i.e. 0 for COMM::0)
+ * @return a newly created CHWPort object
+ */
+	{
+	LOGECUART2(_L8("CHWPort::NewL(), aUint = %d (unit number of comm port)"), aUnit);
+	CHWPort* p = new (ELeave) CHWPort;
+	TCleanupItem closePort(CloseObject, p);
+
+	CleanupStack::PushL(closePort);
+
+	p->iReader=CCommReader::NewL(p);
+	p->iWriter=CCommWriter::NewL(p);
+	p->iBreaker=CCommBreaker::NewL(p);
+	p->iSignalNotifier=new (ELeave) CCommSignalNotifier(p);
+	p->iDataAvailableNotifier=new (ELeave) CCommAvailableDataNotifier(p);
+	p->iFlowControlChangeNotifier=new (ELeave) CCommFlowControlChangeNotifier(p);
+	p->iConfigChangeNotifier=new (ELeave) CCommConfigChangeNotifier(p);
+
+	TName name;
+	name.Format(_L("%d"), aUnit);
+	p->SetName(&name); // todo check return value?
+
+	// the C32 server does not check for the port number beeing to big.
+	// this is up to the CSY. If the aUnit number passed to the Logical
+	// device driver is greater than KMaxUnits, the kernel will Panic.
+	// We want to avoid this by gracefully leaving with Not Supported instead.
+	if(aUnit >= (TUint)KMaxUnits)
+		User::Leave(KErrNotSupported);
+
+	p->iPortName = aUnit;
+#if defined (_DEBUG_CONSOLE_)
+	name.Format(_L("Comm::%d"),aUnit);
+	p->iConsole.SetTitle(name);
+#if defined (_DEBUG_DEVCOMM)
+	p->iDumper=CCommDebugDumper::NewL(p->iConsole);
+#endif
+#endif
+	CleanupStack::Pop();
+	return p;
+	}
+
+
+CHWPort::CHWPort()
+/**
+ * C'Tor
+ */
+	{
+	}
+
+
+void CHWPort::StartRead(const TAny* aClientBuffer, TInt aLength)
+/**
+ * Queue a read
+ *
+ * @param aClientBuffer pointer to the Client's buffer
+ * @param aLength number of bytes to read
+ */
+	{
+	LOGECUART2(_L8("CHWPort::StartRead(), aLength = %d"), aLength);
+	DEBUG_TRACE((iConsole.Write(_L("DoRead \n\r"))));
+	if(iDataAvailableNotifier->IsActive())
+		{
+		ReadCompleted(KErrInUse);
+		return;
+		}
+	iReader->Read(aClientBuffer, aLength);
+	}
+
+
+void CHWPort::ReadCancel()
+/**
+ * Cancel a read
+ */
+	{
+	LOGECUART1(_L8("CHWPort::ReadCancel()"));
+	iReader->ReadCancel();
+	}
+
+
+TInt CHWPort::QueryReceiveBuffer(TInt& aLength) const
+/**
+ * Get the size of the receive buffer from the real serial port
+ *
+ * @param aLength reference to where the size will be written to
+ * @return KErrNone always
+ */
+	{
+	LOGECUART1(_L8("CHWPort::QueryReceiveBuffer()"));
+	// casting away constness with (CHWPort *)this
+	if (iRole==ECommRoleDTE)
+		aLength=((CHWPort *)this)->iPort.QueryReceiveBuffer();
+	else
+		aLength=((CHWPort *)this)->iPortDCE.QueryReceiveBuffer();
+	return KErrNone;
+	}
+
+
+void CHWPort::ResetBuffers(TUint)
+/**
+ * reset Tx and Rx buffers
+ *
+ * @note both Tx and Rx buffers are reset here
+ */
+	{
+	LOGECUART1(_L8("CHWPort::ResetBuffers()"));
+	if (iRole==ECommRoleDTE)
+		iPort.ResetBuffers();
+	else
+		iPortDCE.ResetBuffers();
+	}
+
+
+void CHWPort::StartWrite(const TAny* aClientBuffer, TInt aLength)
+/**
+ * Queue a write
+ *
+ * @param aClientBuffer pointer to the Client's buffer
+ * @param aLength number of bytes to write
+ */
+	{
+	LOGECUART2(_L8("CHWPort::StartWrite(), aLength = %d"), aLength);
+	DEBUG_TRACE((iConsole.Write(_L("DoWrite \n\r"))));
+	iWriter->Write(aClientBuffer,aLength);
+	}
+
+
+void CHWPort::WriteCancel()
+/**
+ * Cancel a pending write
+ */
+	{
+	LOGECUART1(_L8("CHWPort::WriteCancel()"));
+	iWriter->WriteCancel();
+	}
+
+
+void CHWPort::Break(TInt aTime)
+/**
+ * Queue a break
+ *
+ * @param aTime Length of break in micro seconds
+ */
+	{
+	LOGECUART2(_L8("CHWPort::Break(), aTime = %d"), aTime);
+	iBreaker->Break(aTime);
+	}
+
+
+void CHWPort::BreakCancel()
+/**
+ * Cancel a pending break
+ */
+	{
+	LOGECUART1(_L8("CHWPort::BreakCancel()"));
+	iBreaker->Cancel();
+	}
+
+
+TInt CHWPort::GetConfig(TDes8& aDes) const
+/**
+ * Pass a config request
+ *
+ * @param aDes config will be written to this descriptor
+ * @return KErrNone always
+ */
+	{
+	LOGECUART1(_L8("CHWPort::GetConfig()"));
+	if (iRole==ECommRoleDTE)
+		((CHWPort*)this)->iPort.Config(aDes);
+	else
+		((CHWPort*)this)->iPortDCE.Config(aDes);
+	return KErrNone;
+	}
+
+
+TInt CHWPort::SetConfig(const TDesC8& aDes)
+/**
+ * Set up the Comm LDD/PDD
+ *
+ * @param aDes descriptor containing the new config
+ * @return TInt error code
+ */
+	{
+	LOGECUART1(_L8("CHWPort::SetConfig()"));
+	if (aDes.Length()<(TInt)sizeof(TCommConfigV01))
+		return KErrGeneral;
+	TCommConfigV01 config(*(TCommConfigV01*)aDes.Ptr());
+
+	if (config.iHandshake & KConfigWriteBufferedComplete)
+		{
+		if (iWriter->IsNotificationEnabled())
+			return KErrAccessDenied;
+		iEarlyWriteCompletion = ETrue;
+		}
+	else
+		{
+		iEarlyWriteCompletion = EFalse;
+		}
+	if (iRole==ECommRoleDTE)
+		return iPort.SetConfig(aDes);
+	else
+		return iPortDCE.SetConfig(aDes);
+	}
+
+
+TInt CHWPort::SetServerConfig(const TDesC8& aDes)
+/**
+ * Set the port to use partial reads/writes or the bungee buffer
+ *
+ * @param aDes package with new server configurations
+ * @return TInt error code
+ */
+	{
+	LOGECUART1(_L8("CHWPort::SetServerConfig()"));
+	if (aDes.Length()<(TInt)sizeof(TCommServerConfigV01))
+		return KErrGeneral;
+	TCommServerConfig c(*(TCommServerConfigV01*)aDes.Ptr());
+	TInt r=0;
+	if ((r=iReader->SetServerConfig(c))==KErrNone)
+		r=iWriter->SetServerConfig(c);
+	return r;
+	}
+
+
+TInt CHWPort::GetServerConfig(TDes8& aDes)
+/**
+ * Get the server configs
+ *
+ * @param aDes server configs will be written to this descriptor
+ * @return TInt error code
+ */
+	{
+	LOGECUART1(_L8("CHWPort::GetServerConfig()"));
+	if (aDes.Length()<(TInt)sizeof(TCommServerConfigV01))
+		return KErrGeneral;
+	TCommServerConfig c;
+
+	iReader->GetServerConfig(c);
+	aDes=c;
+
+	return KErrNone;
+	}
+
+
+TInt CHWPort::GetCaps(TDes8& aDes)
+/**
+ * Read capabilities from the driver
+ *
+ * @param aDes caps will be written to this descriptor
+ * @return KErrNone always
+ */
+	{
+	LOGECUART1(_L8("CHWPort::GetCaps()"));
+	if (iRole==ECommRoleDTE)
+		iPort.Caps(aDes);
+	else
+		iPortDCE.Caps(aDes);
+	if (aDes.Length()==sizeof(TCommCapsV02))
+		{
+		TCommCapsV02* commcaps = (TCommCapsV02*)(aDes.Ptr());
+		commcaps->iNotificationCaps |= KNotifyOutputEmptySupported;
+		commcaps->iRoleCaps = KCapsRoleSwitchSupported;
+		}
+	return KErrNone;
+	}
+
+
+TInt CHWPort::GetSignals(TUint& aSignals)
+/**
+ * get the status of the signal pins
+ *
+ * @param aSignals signals will be written to this descriptor
+ * @return KErrNone always
+ */
+	{
+	LOGECUART1(_L8("CHWPort::GetSignals()"));
+	if (iRole==ECommRoleDTE)
+		aSignals=iPort.Signals();
+	else
+		aSignals=iPortDCE.Signals();
+	return KErrNone;
+	}
+
+
+TInt CHWPort::SetSignalsToMark(TUint aSignals)
+/**
+ * set selected signals to high (logical 1)
+ *
+ * @param aSignals bitmask with the signals to be set
+ * @return KErrNone always
+ */
+	{
+	LOGECUART2(_L8("CHWPort::SetSignalsToMark(), aSignals = %d"), aSignals);
+	if (iRole==ECommRoleDTE)
+		iPort.SetSignals(aSignals,0);
+	else
+		iPortDCE.SetSignals(aSignals,0);
+	return KErrNone;
+	}
+
+
+TInt CHWPort::SetSignalsToSpace(TUint aSignals)
+/**
+ * set selected signals to low (logical 0)
+ *
+ * @param aSignals bitmask with the signals to be cleared
+ * @return KErrNone always
+ */
+	{
+	LOGECUART2(_L8("CHWPort::SetSignalsToSpace(), aSignals = %d"), aSignals);
+	if (iRole==ECommRoleDTE)
+		iPort.SetSignals(0,aSignals);
+	else
+		iPortDCE.SetSignals(0,aSignals);
+	return KErrNone;
+	}
+
+
+TInt CHWPort::GetReceiveBufferLength(TInt& aLength) const
+/**
+ * get size of Tx and Rx buffer
+ *
+ * @param aLength reference to where the length will be written to
+ * @return KErrNone always
+ */
+	{
+	LOGECUART1(_L8("CHWPort::GetReceiveBufferLength()"));
+	// casting away constness with (CHWPort *)this
+	if (iRole==ECommRoleDTE)
+		aLength=((CHWPort *)this)->iPort.ReceiveBufferLength();
+	else
+		aLength=((CHWPort *)this)->iPortDCE.ReceiveBufferLength();
+	return KErrNone;
+	}
+
+
+TInt CHWPort::SetReceiveBufferLength(TInt aLength)
+/**
+ * set the size of Tx and Rx buffer
+ *
+ * @param aLength new length of Tx and Rx buffer
+ * @return TInt error code
+ */
+	{
+	LOGECUART2(_L8("CHWPort::SetReceiveBufferLength(), aLength = %d"), aLength);
+	if (iRole==ECommRoleDTE)
+		return iPort.SetReceiveBufferLength(aLength);
+	else
+		return iPortDCE.SetReceiveBufferLength(aLength);
+	}
+
+
+void CHWPort::Destruct()
+/**
+ * Destruct - we must (eventually) call delete this
+ */
+	{
+	LOGECUART1(_L8("CHWPort::Destruct()"));
+	delete this;
+	}
+
+
+void CHWPort::FreeMemory()
+/**
+ * Attempt to reduce out memory foot print.
+ */
+	{
+	LOGECUART1(_L8("CHWPort::FreeMemory()"));
+	iReader->FreeMemory();
+	iWriter->FreeMemory();
+	}
+
+
+void CHWPort::NotifySignalChange(TUint aSignalMask)
+/**
+ * notify client when the signals change
+ *
+ * @param aSignalMask bitmask with signal to be notified on
+ */
+	{
+	LOGECUART2(_L8("CHWPort::NotifySignalChange(), aSignalMask = %d"), aSignalMask);
+	iSignalNotifier->NotifySignal(aSignalMask);
+	}
+
+
+void CHWPort::NotifySignalChangeCancel()
+/**
+ * cancel an outstanding signal change notification
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifySignalChangeCancel()"));
+	iSignalNotifier->NotifySignalCancel();
+	}
+
+
+void CHWPort::NotifyConfigChange()
+/**
+ * notify client when the configation changes
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyConfigChange()"));
+	iConfigChangeNotifier->Start();
+	}
+
+
+void CHWPort::NotifyConfigChangeCancel()
+/**
+ * cancel an outstanding config change notification
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyConfigChangeCancel()"));
+	iConfigChangeNotifier->Cancel();
+	}
+
+
+void CHWPort::NotifyFlowControlChange()
+/**
+ * notify client when the flow control changes
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyFlowControlChange()"));
+	iFlowControlChangeNotifier->Start();
+	}
+
+
+void CHWPort::NotifyFlowControlChangeCancel()
+/**
+ * cancel an outstanding flow control change notification
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyFlowControlChangeCancel()"));
+	iFlowControlChangeNotifier->Cancel();
+	}
+
+
+void CHWPort::NotifyBreak()
+/**
+ * notify client when a break occurs
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyBreak()"));
+	iSignalNotifier->NotifyBreak();
+	}
+
+
+void CHWPort::NotifyBreakCancel()
+/**
+ * cancel an outstanding break notification
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyBreakCancel()"));
+	iSignalNotifier->NotifyBreakCancel();
+	}
+
+
+void CHWPort::NotifyDataAvailable()
+/**
+ * notify client when data is available
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyDataAvailable()"));
+	if(iReader->IsActive())
+		{
+		NotifyDataAvailableCompleted(KErrInUse);
+		return;
+		}
+	iDataAvailableNotifier->Start();
+	}
+
+
+void CHWPort::NotifyDataAvailableCancel()
+/**
+ * cancel an outstanding data availalbe notification
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyDataAvailableCancel()"));
+	iDataAvailableNotifier->Cancel();
+	}
+
+
+void CHWPort::NotifyOutputEmpty()
+/**
+ * notify client when output buffer is empty
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyOutputEmpty()"));
+	if (iEarlyWriteCompletion)
+		NotifyOutputEmptyCompleted(KErrAccessDenied);
+	else
+		iWriter->NotificationEnable();
+	}
+
+
+void CHWPort::NotifyOutputEmptyCancel()
+/**
+ * cancel an outstanding output empty notification
+ */
+	{
+	LOGECUART1(_L8("CHWPort::NotifyOutputEmptyCancel()"));
+	iWriter->NotificationDisable();
+	}
+
+
+TInt CHWPort::GetFlowControlStatus(TFlowControl& aFlowControl)
+/**
+ * get the flow control status
+ *
+ * @param aFlowControl flow control status will be written to this descriptor
+ * @return TInt error code
+ *
+ * @note only supported for DCE role
+ */
+	{
+	if (iRole==ECommRoleDTE)
+		return KErrNotSupported;
+	else
+		iPortDCE.GetFlowControlStatus(aFlowControl);
+	return KErrNone;
+	}
+
+
+TInt CHWPort::GetRole(TCommRole& aRole)
+/**
+ * get the role of this port unit
+ *
+ * @param aRole reference to where the role will be written to
+ * @return KErrNone always
+ */
+	{
+	aRole = iRole;
+	return KErrNone;
+	}
+
+
+TInt CHWPort::SetRole(TCommRole aRole)
+/**
+ * set the role of this port unit
+ *
+ * @param aRole the new role
+ * @return TInt error code
+ */
+	{
+	iRole=aRole;
+	TInt ret=KErrNone;
+	if (aRole==ECommRoleDTE)
+		ret = iPort.Open(iPortName);
+	else
+		ret = iPortDCE.Open(iPortName);
+	if (ret!=KErrNone)
+		{
+		LOGECUART3(_L8("CHWPort::SetRole - failed with %d when attempting to open hardware port unit: %d"),ret,iPortName);
+		return ret;
+		}
+	iReader->SetRole(aRole);
+	iWriter->SetRole(aRole);
+	iBreaker->SetRole(aRole);
+	iSignalNotifier->SetRole(aRole);
+	iDataAvailableNotifier->SetRole(aRole);
+	iFlowControlChangeNotifier->SetRole(aRole);
+	iConfigChangeNotifier->SetRole(aRole);
+
+#if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_)
+	iDumper->SetRole(aRole);
+#endif
+	return KErrNone;
+	}
+
+
+CHWPort::~CHWPort()
+/**
+ * D'tor
+ */
+	{
+	LOGECUART1(_L8("CHWPort::~CHWPort()"));
+	delete iReader;
+	delete iWriter;
+	delete iBreaker;
+	delete iSignalNotifier;
+	delete iDataAvailableNotifier;
+	delete iFlowControlChangeNotifier;
+	delete iConfigChangeNotifier;
+
+	iPort.Close();
+	iPortDCE.Close();
+
+#if defined (_DEBUG_CONSOLE_)
+#if defined (_DEBUG_DEVCOMM)
+	delete iDumper;
+#endif
+	iConsole.Close();
+#endif
+	}
+
+
+#ifdef _DEBUG_DEVCOMM
+void CHWPort::DoDumpDebugInfo(const RMessage2 &aMessage)
+	{
+	TCommDebugInfoPckg d;
+	if (iRole==ECommRoleDTE)
+		iPort.DebugInfo(d);
+	else
+		iPortDCE.DebugInfo(d);
+	TRAPD(ret, aMessage.WriteL(0,aMessage,d) );
+	aMessage.Complete(ret);
+	}
+#endif
+
+
+RBusDevComm& CHWPort::DTEPort()
+/**
+ * return the handle to the logical DTE port
+ */
+	{
+	return iPort;
+	}
+
+
+RBusDevCommDCE& CHWPort::DCEPort()
+/**
+ * return the handle to the logical DCE port
+ */
+	{
+	return iPortDCE;
+	}
+
+
+//
+// todo implement this - for further improvements
+//
+#if 0
+RBusWhatever& CHWPort::Port()
+/**
+ * return a handle to our port
+ */
+	{
+	if (iRole==ECommRoleDTE)
+		return iPort;
+	else
+		return iPortDCE;
+	}
+#endif
+
+
+//
+// implementation of CHWPortFactory
+//
+
+
+CHWPortFactory::CHWPortFactory()
+/**
+ * C'tor
+ */
+	{
+	TName name(SERIAL_NAME);
+	SetName(&name); // todo check return value?
+	iVersion = TVersion(KEC32MajorVersionNumber, KEC32MinorVersionNumber, KEC32BuildVersionNumber);
+	}
+
+
+CPort* CHWPortFactory::NewPortL(const TUint aUnit)
+/**
+ * Create a new port for the supplied unit number
+ *
+ * @param aUnit port unit number (i.e. 0 for COMM::0)
+ */
+	{
+	LOGECUART2(_L8("CHWPortFactory::NewPortL(), aUnit = %d"), aUnit);
+//	__ASSERT_ALWAYS(aUnit>=KCommLowUnit,User::Leave(KErrNotSupported));
+//	__ASSERT_ALWAYS(aUnit<=KCommHighUnit,User::Leave(KErrNotSupported));
+	return (CPort *)CHWPort::NewL(aUnit);
+	}
+
+
+void CHWPortFactory::Info(TSerialInfo& aSerialInfo)
+/**
+ * get info about this CSY, fill in the supplied structure.
+ *
+ * @param aSerialInfo where info will be written to
+ */
+	{
+	aSerialInfo.iDescription = KSerialDescription;
+	aSerialInfo.iName = SERIAL_NAME;
+	aSerialInfo.iLowUnit = KCommLowUnit;
+	aSerialInfo.iHighUnit = KCommHighUnit;
+	}
+
+/**
+Returns capabilities for requested port
+*/
+TSecurityPolicy CHWPortFactory::PortPlatSecCapability(TUint aPort) const
+	{
+	LOGECUART2(_L8("CHWPortFactory::PortPlatSecCapability(), aPort = %d"), aPort);
+	TSecurityPolicy csySecurityPolicy(KDefaultPortPassPolicy);
+
+	if(aPort >= (TUint)KMaxUnits)	//if greater than KMaxUnits it is an invalid port so fail.
+		{
+		csySecurityPolicy = KPortAlwaysFailPolicy;
+		}
+	else //see if it is defined in explicit policy list.
+		{
+		for(int i = 0;i < KExplicitPortPoliciesCount; i++)
+			{
+			// coverity [dead_error_line] : KExplicitPortPoliciesCount is currently 0, but this could change.
+			if(aPort == KExplicitPortSecurityPolicies[i].iPort)
+				{
+				csySecurityPolicy = KExplicitPortSecurityPolicies[i].iPolicy;
+				break;
+				}
+			}
+		}
+	return csySecurityPolicy;
+	}
+
+extern "C"
+	{
+	IMPORT_C CSerial* LibEntry(void);   // Force export
+	};
+
+
+EXPORT_C CSerial* LibEntry()
+/**
+ * Lib main entry point
+ */
+	{
+	LOGECUART1(_L8("LibEntry()"));
+	return new CHWPortFactory;
+	}
+
+
+#if defined(_DEBUG_CONSOLE_)
+
+RDebugConsole::RDebugConsole()
+	{
+	Create();
+	Set(_L(""),TSize(64,15));
+
+	}
+
+void RDebugConsole::Printf(TRefByValue<const TDesC> aFmt,...)
+//
+// Print to a console screen.
+//
+	{
+
+	VA_LIST list;
+	VA_START(list,aFmt);
+	TBuf<0x100> aBuf;
+	aBuf.AppendFormatList(aFmt,list);
+	Write(aBuf);
+	}
+#endif
+
+#if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_)
+CCommDebugDumper* CCommDebugDumper::NewL(RDebugConsole &aConsole)
+	{
+	CCommDebugDumper* p=new CCommDebugDumper(aConsole);
+	return p;
+	}
+
+CCommDebugDumper::CCommDebugDumper(RDebugConsole &aConsole)
+	:CActive(EPriorityStandard)
+	{
+	iRole=ECommRoleDTE;
+	iConsole=&aConsole;
+	CActiveScheduler::Add(this);
+	SetActive();
+	iConsole->Read(iKeystroke,iStatus);
+	};
+
+CCommDebugDumper::~CCommDebugDumper()
+	{
+	Cancel();
+	}
+
+void CCommDebugDumper::RunL()
+	{
+	TInt key=iKeystroke.Code();
+	switch(key)
+		{
+		case 'd':
+		case 'D':
+			{
+			TCommDebugInfoPckg d;
+			if (iRole==ECommRoleDTE)
+				iParent->DTEPort().DebugInfo(d);
+			else
+				iParent->DCEPort().DebugInfo(d);
+			TCommDebugInfo& debug=d();
+			iConsole->Printf(_L("rxbusy  : 0x%04x, rxHeld   : 0x%04x, \n\r"),debug.iRxBusy,debug.iRxHeld);
+			iConsole->Printf(_L("txbusy  : 0x%04x, txHeld   : 0x%04x, \n\r"),debug.iTxBusy,debug.iTxHeld);
+			iConsole->Printf(_L("drainRx : 0x%04x, fillTx   : 0x%04x\n\r"),debug.iDrainingRxBuf,debug.iFillingTxBuf);
+			iConsole->Printf(_L("Txonchar: 0x%04x, TxOffchar: 0x%04x\n\r"),debug.iTxXon,debug.iTxXoff);
+			iConsole->Printf(_L("RxonChar: 0x%04x, RxOffchar: 0x%04x\n\r"),debug.iRxXon,debug.iRxXoff);
+			iConsole->Printf(_L("NumTX   : 0x%04x, NumRx    : 0x%04x\n\r"),debug.iTxChars,debug.iRxChars);
+			iConsole->Printf(_L("TxLen   : 0x%04x, RxLen    : 0x%04x\n\r"),debug.iTxLength,debug.iRxLength);
+			iConsole->Printf(_L("TxOffset: 0x%04x, RxOffset : 0x%04x\n\r"),debug.iTxOffset,debug.iRxOffset);
+			iConsole->Printf(_L("TxInts  : 0x%04x, RxInts   : 0x%04x\n\r"),debug.iTxIntCount,debug.iRxIntCount);
+			}
+			break;
+		case 's':
+		case 'S':
+			{
+			TUint signals=0;
+			if (iRole==ECommRoleDTE)
+				signals=iParent->DTEPort().Signals();
+			else
+				signals=iParent->DCEPort().Signals();
+			iConsole->Printf(_L("Signals: "));
+			if (signals&KSignalCTS)
+				iConsole->Printf(_L("CTS "));
+			if (signals&KSignalDSR)
+				iConsole->Printf(_L("DSR "));
+			if (signals&KSignalDCD)
+				iConsole->Printf(_L("DCD "));
+			if (signals&KSignalRTS)
+				iConsole->Printf(_L("RTS "));
+			if (signals&KSignalDTR)
+				iConsole->Printf(_L("DTR "));
+			iConsole->Printf(_L("\n\r"));
+			}
+			break;
+		default:
+			break;
+		}
+
+	SetActive();
+	iConsole->Read(iKeystroke,iStatus);
+	};
+
+void CCommDebugDumper::DoCancel()
+	{
+	iConsole->ReadCancel();
+	}
+
+#endif
+
+// EOF - ECUART.CPP