basebandadaptationplugins/basebandchanneladaptorforc32/c32bca2/src/C32Bca.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/basebandadaptationplugins/basebandchanneladaptorforc32/c32bca2/src/C32Bca.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1198 @@
+// Copyright (c) 2004-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:
+// C32 Baseband Channel Adaptor(BCA) APIs implementation.
+// This file contains all the API implementation of the C32BCA interface for Symbian OS.
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "C32Bca.h"
+#include <cdbcols.h>
+#include <commsdat_partner.h>
+
+using namespace BasebandChannelAdaptation;
+using namespace BasebandChannelAdaptation::C32Bca;
+
+const static TUint KVersion = ((static_cast<TUint>(KC32BcaMajorVersionNumber)) << 16) | KC32BcaMinorVersionNumber;
+
+
+/**
+C++ constructor for an object representing a c32 async user
+
+@param aUser the target of the notifications originating in C32
+@param aPort the C32 port to be used with this object
+@param aAoPriority the priority to assign to this active object
+*/
+CCommBase::CCommBase(MC32User& aUser, RComm& aPort, TInt aAoPriority):
+	CActive(aAoPriority),
+	iUser(aUser),
+	iPort(aPort)
+	{
+	CActiveScheduler::Add(this);
+	__FLOG_OPEN(KC32BcaLogFolder, KC32BcaLogFile); // Connect to the BCA logger			
+	}
+		
+/**
+C++ destructor */		
+CCommBase::~CCommBase()
+	{
+	__FLOG_CLOSE;
+	}
+
+/**
+C++ constructor 
+The comm-reader has a higher priority than the comm-writer, to
+ensure the reader gets the chance to receive the incomming data
+
+@param aUser the target of the notifications originating in C32
+@param aPort the C32 port to be used with this object
+*/
+CCommReader::CCommReader(MC32User& aUser, RComm& aPort):
+	CCommBase(aUser, aPort, EPriorityHigh)
+	{
+	}
+
+/** 
+C++ destructor */
+CCommReader::~CCommReader()
+	{
+	Cancel();
+	}
+
+/**
+Cancels the outstanding read */
+void CCommReader::DoCancel()
+	{
+	iPort.ReadCancel();
+	}
+		
+/**
+Issues a read on the serial port 
+
+@param aBuf the buffer to read to */		
+void CCommReader::Read(TDes8& aBuf)
+	{
+	iPort.ReadOneOrMore(iStatus, aBuf);	
+	SetActive();
+	}
+
+/**
+Called on read completion */	
+void CCommReader::RunL()
+	{
+	iUser.CommReadComplete(iStatus.Int());
+	}
+	
+/**
+C++ constructor
+The comm-writer has a lower priority than the comm-reader, to
+ensure the reader gets the chance to receive the incomming data
+
+@param aUser the target of the notifications originating in C32
+@param aPort the C32 port to be used with this object */	
+CCommWriter::CCommWriter(MC32User& aUser, RComm& aPort):
+	CCommBase(aUser, aPort, EPriorityUserInput)
+	{
+	}
+
+/** 
+C++ destructor */
+CCommWriter::~CCommWriter()
+	{
+	Cancel();
+	}
+
+/**
+Issues a write on the serial port */
+void CCommWriter::Write(const TDesC8& aBuf)
+	{
+	iPort.Write(iStatus, aBuf);
+	SetActive();
+	}
+		
+/**
+Called when the write completes
+*/
+void CCommWriter::RunL()
+	{
+	iUser.CommWriteComplete(iStatus.Int());
+	}
+
+/**
+Cancels the outstanding write
+*/
+void CCommWriter::DoCancel()
+	{
+	iPort.WriteCancel();
+	}
+		
+/**
+C++ constructor
+
+@param aUser the target of the notifications originating in C32
+@param aPort the C32 port to be used with this object
+
+
+Note on Monitor AO priority:
+
+Monitor AO is the same priority as the Reader / Writer by design. 
+
+We do NOT want link failure notification to complete before all possible outstanding reads / writes
+have completed, to make sure that we do not lose any data that was already received from the
+baseband and is buffered by the driver or the CSY.
+Consider a scenario where a UDP datagram is received by the CSY, and then the serial link is
+severed (e.g. cable is unplugged by the user). If the Monitor has higher priority than reader/writer,
+we may get failure notification before we are notified on the read of this UDP datagram, potentially
+resulting in its loss (E.g. PPP shuts down when on Link Down notification.)
+*/	
+CCommLinkMonitor::CCommLinkMonitor(MC32User& aUser, RComm& aPort):
+	CCommBase(aUser, aPort, EPriorityStandard) 
+	{
+	}
+
+/**
+Sets the object to monitor the link for the configured Role, DTE or DCE
+
+@param aMask DTE or DCE: determines when the link is considered to be down.
+*/
+void CCommLinkMonitor::Setup(TUint32 aMask)
+	{
+	iNotifyChangeSignalMask = aMask;	
+	__FLOG_1(_L8("CommLinkMonitor setup: Notify on signal mask [0x%X]"),iNotifyChangeSignalMask);
+	}
+
+/**
+Requests to be notified when the link is down.
+
+Can be called an more than once
+*/
+void CCommLinkMonitor::NotifyLinkDown()
+	{
+	ASSERT(!IsActive());
+		
+	// get the current state of the line so when we get notification we can tell if it really has changed	
+	iSavedSignalState = iPort.Signals(iNotifyChangeSignalMask) & iNotifyChangeSignalMask;
+	iPort.NotifySignalChange(iStatus, iSignals, iNotifyChangeSignalMask);
+
+	__FLOG_1(_L8("CommLinkMonitor::NotifyLinkDown: initial signals: [0x%X]"), iSavedSignalState);
+	
+	SetActive();
+	}
+
+/**	
+Called when EIA-232 signals change,i.e. on potential link failure
+*/
+void CCommLinkMonitor::RunL()
+	{
+	__FLOG_2(_L8("CommLinkMonitor::RunL: Signals changed [0x%X]; new signals [0x%X]"), iSignals & (~0x1F), iSignals & 0x1F);
+	
+	// We report link failure if and only if a monitored line went from high to low.
+	// Method: mask the saved signals using inverted monitored bits in the signal bitmask,
+	// to filter out all transitions except for high -> low. 
+	// 1 & ~0 = 1;    1 & ~1 = 0; 0 & ~1 = 0; 0 & ~0 = 0
+	// This is necessary, because we may be monitoring more than one signal, and the change can be arbitrary.
+	if ((~(iNotifyChangeSignalMask & iSignals)) & iSavedSignalState) 
+		{		
+		iUser.CommLinkDown(KErrCommsLineFail);
+		}
+	iSavedSignalState = iSignals & iNotifyChangeSignalMask;	// update saved state with relevant bits	
+	iPort.NotifySignalChange(iStatus, iSignals, iNotifyChangeSignalMask);
+	SetActive(); 
+	// Note: If the link went down, the user will likely shutdown the BCA on outstanding signal notification. 
+	}
+
+/**
+Cancels notification request of link failure */	
+void CCommLinkMonitor::DoCancel()
+	{
+	__FLOG(_L8("CommLinkMonitor::DoCancel: Cancelling signal change notification."));
+	iPort.NotifySignalChangeCancel();
+	}
+	
+
+
+
+
+/**
+* default constructor to create a C32Bca instance.
+*/
+CC32Bca::CC32Bca()	
+	{
+	__FLOG_OPEN(KC32BcaLogFolder,KC32BcaLogFile);
+	__FLOG_2(_L8("====== CC32Bca::CC32Bca: Shim BCA for C32 [Vesion: major= %d minor= %d] Constructed. ======"), KC32BcaMajorVersionNumber, KC32BcaMinorVersionNumber);
+	}
+
+/**
+2nd phase of construction: allocates member objects 
+
+
+@leave when members cannot be constructed. */
+void CC32Bca::ConstructL()
+	{
+	__ASSERT_DEBUG(!iReader, Panic(EReaderAlreadyExists));
+	__ASSERT_DEBUG(!iWriter, Panic(EWriterAlreadyExists));
+	__ASSERT_DEBUG(!iLinkMonitor, Panic(EMonitorAlreadyExists));
+	
+	// Comm is not initialized yet. We have to be Opened before it can be used. C32 panics otherwise.
+	iReader = new (ELeave)CCommReader(*this, iComm);
+	iWriter = new (ELeave)CCommWriter(*this, iComm);
+	// Monitor is created upon user request only, we may never need it at all.
+	}
+
+/**
+* Destructor 
+*/	
+CC32Bca::~CC32Bca()
+	
+	{
+	__FLOG(_L8("CC32Bca::~CC32Bca: releasing resources..."));
+		
+	CloseCommDbConnection(); 
+	CloseCommPort(); 	// Cancels reader / writer / monitor
+	
+	// N.B.: 
+	// It is critical that these objects are cancelled before deletion. Else DoCancel operates on closed C32 port, 
+	// causing C32 to panic. 
+	delete iReader;
+	delete iWriter;
+	delete iLinkMonitor; // Note: may have never been created.
+
+	__FLOG(_L8("CC32Bca::~CC32Bca: CC32Bca destroyed."));
+	__FLOG_CLOSE;
+	}
+	
+/** This method deletes the BCA itself.*/
+void CC32Bca::Release()
+	{
+	__FLOG(_L8("CC32Bca::Release"));
+	delete this;
+	}
+	
+/**
+* Informs that the BCA is required by the client(for instance, Raw IP NIF).Comms Server is
+* connected, and serial port is opened.
+	
+* @param aStatus complete status, KErrNone if successful, C32 error code otherwise.
+* @param aChannelId comm port name.
+*/	
+void CC32Bca::Open(TRequestStatus& aStatus, const TDesC& aChannelId)
+	{
+	// We don't have the ConstructL, so we have to allocate memory here.
+	
+	aStatus = KRequestPending;
+	// avoid compiler warning.
+	TRequestStatus* ptrStatus = &aStatus;
+	if(iCommPortOpen)
+		{
+		__FLOG(_L8("Warning: C32Bca is already Opened."));
+	
+		User::RequestComplete(ptrStatus,KErrNone);
+		return;	
+		}
+	
+	if(aChannelId == KChannelIdNotOverridden) // Channel ID is not supplied - Comm Port Name is not overriden.
+		{									 // Read it from CommDB.
+		// Fetch port name from CommDB.
+		TRAPD(commPortErr, ReadCommPortFromCommDbL(iCommPort));
+		
+		// If the column is missing from CommDB, we can get an empty string with KErrNone.
+		// Opening RComm with empty string as Port name fails with ECUART, LOOOPBACK CSYs. 
+		// with different error codes on 8.1 and 9.0. 
+		// It would be better to intercept such invalid value and fail here.
+		// This is not done, because theoretically it is possible to write a CSY that somehow takes an 
+		// emty descriptor as a port name. As of December 2004, C32 does not allow that, however, this
+		// may change in the future.
+		// So, we just log a warning.
+		if(KErrNone == commPortErr && iCommPort.Size() == 0)
+			{
+			__FLOG(_L8("Warning: Null string read from CommDB. Will try to open Comm Port anyway."));
+			}		
+		
+		if(KErrNone != commPortErr) // Fatal: we do not have a port name. Can't open RComm.
+			{
+			__FLOG(_L8("Error: Failed to get C32 PortName from CommDB "));
+			CloseCommDbConnection();
+			User::RequestComplete(ptrStatus, commPortErr);
+			return;
+			}		
+		}
+	else // Channel ID supplied - use it as Port Name.
+		{
+		_LIT(KDoubleColon, "::");
+		TInt len1 = aChannelId.Find(KDoubleColon);
+
+		if (len1 < KErrNone)
+			{
+			__FLOG(_L8("** ERROR: No :: (Double Colon) in aChannelId **"));
+			User::RequestComplete(ptrStatus, KErrBadName);
+			return;	
+			}
+		else
+			{
+			TUint numPos = len1 + KDoubleColon.iTypeLength;
+						
+			TInt len2 = (aChannelId.Mid(numPos)).Find(KDoubleColon);
+			
+			if (len2 < KErrNone)
+				{
+				iCommPort = aChannelId;
+				}
+			else
+				{
+				iCommPort = aChannelId.Mid(numPos);
+				iCsyName = aChannelId.Mid(0, len1);
+				iCsyNameOverride = ETrue;
+				}
+			}
+		}
+	// We have the Port Name at this point: either supplied as a parameter, or read from CommDB.
+
+	if(!iCsyNameOverride) // CSY name is not provisioned by Ioctl: read it from CommDB.
+		{
+		TRAPD(getCsyErr, ReadCsyNameFromCommDbL(iCsyName));
+		if(KErrNone != getCsyErr) // Fatal: we do not have a CSY name. Can't load CSY module.
+			{
+			// We do not use a hardcoded value (e.g. ECUART), because the client code or the environment are
+			// confused - it is better to fail them, rather than mask their problems.
+			__FLOG(_L8("Error: Failed to get CSY name from CommDB "));
+			CloseCommDbConnection();
+			User::RequestComplete(ptrStatus,getCsyErr);
+			return;
+			}
+		}
+	// We have the CSY name at this point, either provisioned via Ioctl, or read from CommDB.
+
+	// Decide the Comm Role (DCE / DTE) of the port.
+	TBool isCommRoleDefault = EFalse;
+	// We use a concept of "Default Comm Role", because C32 has it. We could use DTE as a default
+	// setting, but we prefer to call the "default" method on C32 and let it decide what the role should be.
+
+	if(!iCommRoleOverride) // Port role not overriden via Ioctl
+		{
+		TRAPD(getCommRoleErr, ReadCommRoleFromCommDbL(iCommRole));
+		if(KErrNone != getCommRoleErr) // Port role not specified via CommDb
+			{
+			isCommRoleDefault = ETrue; // Port role not specified via Ioctl or CommDb
+			}
+		}
+	// We have the Comm Role: provisioned via Ioctl, read from CommDB, or default(DTE)
+	
+	CloseCommDbConnection(); // We do not read any settings once the connection is opened. 	
+	// We have all the necessary C32 settings at this point.
+	// Open the actual C32 session:
+	
+	TInt ret = iCommServ.Connect();
+	if(ret)
+		{
+		__FLOG_1(_L8("Open: C32 Server connection error %d"), ret);
+		User::RequestComplete(ptrStatus,ret);
+		return;
+		}
+	ret = iCommServ.LoadCommModule(iCsyName);
+	
+	__FLOG_2(_L16("Open: CSY module [%S] loaded with error %d"), &iCsyName, ret);
+		
+	if(ret)
+		{
+		User::RequestComplete(ptrStatus,ret);
+		return;
+		}
+	
+	if(isCommRoleDefault)
+		{
+		ret = iComm.Open(iCommServ, iCommPort, ECommShared);
+		}
+	else
+		{
+		ret = iComm.Open(iCommServ, iCommPort, ECommShared, iCommRole);	
+		}
+	
+	__FLOG_2(_L16("Open: C32 port [%S] opened with error %d"), &iCommPort, ret);
+					
+	if(ret)
+		{
+		User::RequestComplete(ptrStatus,ret);
+		return;
+		}
+	//
+	//Open successfull, we update our state.
+	//
+	
+	// We may have been closed, and are being reopened now. Make sure no errors persist from the previous session.
+	iErrorOnNextRead  = KErrNone; 
+	iErrorOnNextWrite = KErrNone;
+	iCommPortOpen = ETrue;
+	
+	User::RequestComplete(ptrStatus,KErrNone);
+	// Don't start control line monitoring. This is done on user request via Ioctl only.
+	}
+	
+/**
+ Shuts the BCA channel down in a graceful manner. BCA releases its resources.
+ Cancels all outstanding operations: Writes, Reads and Ioctls.
+
+ Due to the specifics of C32Bca implementation, this call completes immediately and is identical to ::Close.
+ 
+ @param aStatus completion status: Always KErrNone.
+*/	
+void CC32Bca::Shutdown(TRequestStatus& aStatus)
+	{
+	aStatus = KRequestPending;
+	
+	CloseCommPort();
+	
+	// Don't notify reader / writer / monitor. Read / Write should not be called after this anyway. Let C32 panic.
+	
+	TRequestStatus* request = &aStatus;
+	User::RequestComplete(request, KErrNone);
+	__FLOG_1(_L8("C32Bca::Shutdown: BCA shut down with error %d"), KErrNone);
+	}
+
+/**
+* Closes the BCA immediately. BCA releases its resources.
+* cancels all Writes, Reads and Controls.
+*/	
+void CC32Bca::Close()
+	{
+	CloseCommPort();
+	__FLOG_1(_L8("C32Bca::Close:Close: BCA closed with error %d"), KErrNone);
+	}
+
+/**
+* Queues a Read on C32 serial port.
+
+* @param aStatus complete status, KErrNone if successful, C32 error code otherwise.
+* @param aBuf buffer for data to be read.
+* @note The buffer is owned by the client. Client must not access / modify the buffer until the Read completes.
+*/	
+void CC32Bca::Read(TRequestStatus& aStatus,TDes8& aBuf)
+	{
+	iReadRequest = &aStatus;
+	*iReadRequest = KRequestPending;
+
+	if(iErrorOnNextRead)
+		{
+		User::RequestComplete(iReadRequest, iErrorOnNextRead);
+		// Error persists until the BCA is closed and opened
+		}
+	else
+		{
+		iReader->Read(aBuf);	
+		}
+	}
+
+/**
+* Queues a Write on C32 serial port.
+
+* @param aStatus the complete status, KErrNone if successful, C32 error code otherwise.
+* @param aBuf the buffer to sent.
+* @note The buffer is owned by the client. Client must not access / modify the buffer until the Write completes.
+*/	
+void CC32Bca::Write(TRequestStatus& aStatus,const TDesC8& aBuf)
+	{
+	iWriteRequest = &aStatus;
+	*iWriteRequest = KRequestPending;
+	
+	if(iErrorOnNextWrite)
+		{
+		User::RequestComplete(iWriteRequest, iErrorOnNextWrite);
+		// Error persists until BCA is closed and opened.
+		}
+	else
+		{
+		iWriter->Write(aBuf);	
+		}
+	}
+
+/**
+ Cancels the outstanding Read operation.(best effort operation: the read may have been completed already.)
+*/	
+void CC32Bca:: CancelRead()
+	
+	{
+	__FLOG(_L8("CancelRead: Read is cancelled by client."));
+	iReader->Cancel();
+
+	if(iReadRequest != NULL)
+		{
+		User::RequestComplete(iReadRequest, KErrCancel);
+		}
+	}
+
+/**
+ Cancels all Write operations.(best effort attempt: the write may have been completed already.)
+*/	
+void CC32Bca::CancelWrite()
+
+    {
+    __FLOG(_L8("CancelWrite: Write is cancelled by client."));
+
+    iWriter->Cancel();
+
+    if(iWriteRequest != NULL)
+    	{
+    	User::RequestComplete(iWriteRequest, KErrCancel);
+    	}
+    }
+    
+
+// Debug dumps:
+#ifdef __FLOG_ACTIVE
+
+_LIT8(KLitOptLevelGeneric,    "KBcaOptLevelGeneric");
+_LIT8(KLitOptLevelExtSerial,   "KBcaOptLevelExtSerial");
+_LIT8(KLitOptLevelUnsupported, "**Unsupported**");
+
+/**
+Returns a string for an option level
+
+@param aOptLevel BCA Option Level 
+@return readable string for aOptLevel
+*/
+static const TDesC8& IoctlOptLevelStr(TUint32 aOptLevel)
+	{
+	switch(aOptLevel)
+		{
+		case KBcaOptLevelGeneric:
+			return KLitOptLevelGeneric;
+		case KBcaOptLevelExtSerial:
+			return KLitOptLevelExtSerial;
+		default: 
+			return KLitOptLevelUnsupported;
+		}
+	}
+
+
+_LIT8(KLitOptNameBcaVersionNumber, "KBcaOptNameVersionNumber");
+_LIT8(KLitOptNameBcaCaps,    	   "KBcaOptNameBcaCaps");
+_LIT8(KLitOptNameBcaSetIapId,      "KBcaOptNameBcaSetIapId");
+_LIT8(KLitOptNameBcaSetBcaStack,   "KBcaOptNameBcaSetBcaStack");
+_LIT8(KLitOptNameBcaResetBuffers,  "KBcaOptNameBcaResetBuffers");
+_LIT8(KLitOptNameSerialPortName,   "KBcaOptNameSerialPortName");
+_LIT8(KLitOptNameSerialConfig,     "KBcaOptNameSerialSerialConfig");
+_LIT8(KLitOptNameSerialSetConfig,  "KBcaOptNameSerialSerialSetConfig");
+_LIT8(KLitOptNameSerialSetCsyName,  "KBcaOptNameBcaSetCsyName");
+_LIT8(KLitOptNameSerialSetCommRole, "KBcaOptNameSetCommRole");
+_LIT8(KLitSerialSetTxRxBufferSize,  "KSerialSetTxRxBufferSize");
+_LIT8(KLitSerialTxRxBufferSize, 	"KSerialTxRxBufferSize");
+_LIT8(KLitSerialMonitorControlLines, "KSerialMonitorControlLines");
+_LIT8(KLitSerialSetControlLines,	"KSerialSetControlLines");
+_LIT8(KLitOptNameUnsupported,  	   "**Unsupported**");	
+
+
+/**
+Returns a string for the given option name
+
+@param aOptLevel BCA Option Name 
+@return readable string for aOptName
+*/
+static const TDesC8& IoctlOptNameStr(TUint32 aOptName)
+	{
+	switch(aOptName)
+		{
+		case KBCACaps:
+			return KLitOptNameBcaCaps;
+		case KVersionNumber:
+			return KLitOptNameBcaVersionNumber;
+		case KBCASetIapId:
+			return KLitOptNameBcaSetIapId;
+		case KBCASetBcaStack:
+			return KLitOptNameBcaSetBcaStack;
+		case KBCAResetBuffers:
+			return KLitOptNameBcaResetBuffers;
+		case KSerialPortName:
+			return KLitOptNameSerialPortName;
+		case KSerialConfig:
+			return KLitOptNameSerialConfig;
+		case KSerialSetConfig:
+			return KLitOptNameSerialSetConfig;
+		case KSerialSetCsyName:
+			return KLitOptNameSerialSetCsyName;
+		case KSerialSetCommRole:
+			return KLitOptNameSerialSetCommRole;
+		case KSerialSetTxRxBufferSize:
+			return KLitSerialSetTxRxBufferSize;
+		case KSerialTxRxBufferSize:
+			return KLitSerialTxRxBufferSize;
+		case KSerialMonitorControlLines:
+			return KLitSerialMonitorControlLines;		
+		case KSerialSetControlLines:
+			return KLitSerialSetControlLines;
+		default:
+			return KLitOptNameUnsupported;		
+		}
+	}
+#endif // __FLOG_ACTIVE
+
+
+#ifdef __FLOG_ACTIVE
+/**
+Print debug output of the TCommComfig parameters.
+
+@param The configuration whose parameters should be logged.
+*/
+void CC32Bca::LogCommConfig(TCommConfig& c)
+	{
+	__FLOG_5(_L8("Rate[%d] DataBits[%d] StopBits[%d] Parity[%d] Handshake[0x%x]"), c().iRate, c().iDataBits, c().iStopBits, c().iParity, c().iHandshake);	
+	__FLOG_4(_L8("ParityError[%d] Fifo[%d] SpecialRate[%d] terminatorCount[%d]"), c().iParityError, c().iFifo, c().iSpecialRate, c().iTerminatorCount);	
+	__FLOG_1(_L8("Terminator[0x%x]"), c().iTerminator);	
+	}
+#endif // __FLOG_ACTIVE
+
+
+/**
+* Ioctl: asynchronously controls the C32Bca.
+
+* @param aStatus complete status, KErrNone if successful, system-wide error code otherwise.
+* @param aOptLevel option level to be used.
+* @param aOptName option name to be used.
+* @param aOpt an optional parameter,holds the option value on return or the option value to be set.
+*/  
+void CC32Bca::Ioctl(TRequestStatus& aStatus, TUint aOptLevel, TUint aOptName, TDes8& aOpt)
+
+	{
+	__FLOG_4(_L8("Ioctl: Level[%S](0x%X) Name[%S](0x%X)."), &IoctlOptLevelStr(aOptLevel), aOptLevel, &IoctlOptNameStr(aOptName), aOptName);	
+	
+	aStatus = KRequestPending;
+	
+	TInt ret(KErrNone); // If operation fails, this will be set to the failure code explicitly.
+	
+	// Don't check the port status. Let C32 panic. It's the caller's responsibility to make sure that
+	// the port is in a valid state (for most operations, open & not having any Tx Rx ops outstanding)
+	if(aOptLevel == KBcaOptLevelGeneric)
+		{
+		switch(aOptName)
+			{
+			case KBCACaps:
+				{
+				const TPckg<TUint> capPckg(KBcaCapSerial);
+				aOpt = capPckg;			
+				break;
+				}
+				
+			case KVersionNumber:
+				{
+				const TPckg<TUint> versionPckg(KVersion); //lower 16 contains KC32BcaMinorversionNumber, upper 16 bit contains KC32BcaMajorVersionNumber.
+				aOpt = versionPckg;
+				break;
+				}
+				
+			case KBCASetIapId:
+				{
+				TUint32 tempIapId = *(reinterpret_cast<const TUint32*>(aOpt.Ptr()));
+				
+				__FLOG_1(_L8("Ioctl: IAP ID [%d] specified."),tempIapId);	
+				
+				if(tempIapId < 1 )
+					{
+					ret = KErrArgument;
+					}
+				else
+					{
+					iIapId = tempIapId;
+					}
+				break;
+				}
+				
+			case KBCAResetBuffers:
+				{
+				TUint resetBufMaskArg = *(reinterpret_cast<const TUint32*>(aOpt.Ptr()));
+				TUint resetBufMask(0x0);
+		
+				if(resetBufMaskArg & KResetRxBuf)
+					{
+					resetBufMask |= KCommResetRx;
+					}
+				if(resetBufMaskArg & KResetTxBuf)
+					{
+					resetBufMask |= KCommResetTx;
+					}
+				ret = iComm.ResetBuffers(resetBufMask);
+				break;
+				}
+			
+				
+			default:
+				{
+				ret = KErrNotSupported;
+				}
+			}
+		}		
+	else if(aOptLevel == KBcaOptLevelExtSerial)
+		{
+		switch(aOptName)
+			{
+		case KSerialCaps:
+			{
+			iComm.Caps(aOpt);
+			break;
+			}
+			
+		case KSerialConfig:
+			{
+			__FLOG(_L8("Ioctl: KSerialConfig"));	
+
+			TCommConfig cfg;
+			iComm.Config(cfg);
+
+#ifdef __FLOG_ACTIVE
+			LogCommConfig(cfg);
+#endif // __FLOG_ACTIVE
+
+			TPckgBuf<TCommConfig> cfgBuf(cfg);
+			aOpt.Copy(cfgBuf);
+			break;
+			}
+
+		case KSerialSetConfig:
+			{
+			__FLOG(_L8("Ioctl: KSerialSetConfig"));	
+
+			TCommConfig cfg(*(reinterpret_cast<const TCommConfig*>(aOpt.Ptr())));
+
+#ifdef __FLOG_ACTIVE
+			LogCommConfig(cfg);
+#endif // __FLOG_ACTIVE
+
+			ret = iComm.SetConfig(cfg);
+			break;
+			}
+			
+		case KSerialPortName:
+			{
+			aOpt.Copy(iCommPort);
+			break;
+			}
+			
+		case KSerialSetCsyName:
+			{
+			if(!iCommPortOpen)
+				{
+				iCsyName.Copy(*(
+			   				reinterpret_cast<const TName*>(aOpt.Ptr())
+			   				));
+				iCsyNameOverride = ETrue;
+				__FLOG_1(_L8("Ioctl: CSY Name set to [%S]"), &iCsyName);	
+				}
+			else
+				{
+				__FLOG(_L8("Ioctl: Warning: Cannot set the CSY name because the Comm Port is already open."));
+				ret = KErrAlreadyExists;
+				}
+			
+			break;
+			}
+			
+		case KSerialSetCommRole:
+			{
+			if(!iCommPortOpen)
+				{
+				iCommRole = *(reinterpret_cast<const TCommRole*>(aOpt.Ptr()));
+				iCommRoleOverride = ETrue;
+				__FLOG_1(_L8("Ioctl: Comm Role set to [%d]"), iCommRole);	
+				}
+			else
+				{
+				__FLOG(_L8("Ioctl: Warning: Cannot set Comm Role because the Comm Port is already open."));
+				ret = KErrAlreadyExists;
+				}
+			break;	
+			}
+		
+		case KSerialSetTxRxBufferSize:
+			{
+			TInt bufSize = *(reinterpret_cast<const TInt*>(aOpt.Ptr()));
+			__FLOG_1(_L8("Ioctl: Setting Rx Tx buffer size to [%d]"), bufSize); 
+			
+			iComm.SetReceiveBufferLength(bufSize);
+			break;
+			}
+			
+		case KSerialMonitorControlLines:
+			{
+			TRAP(ret, MonitorControlLinesL(*(reinterpret_cast<const TUint*>(aOpt.Ptr()))));
+			break;
+			}			
+							
+		case KSerialSetControlLines:
+			{
+			if (aOpt.Length() != sizeof(TSerialSetControlLines))
+				{
+				ret = KErrArgument;
+				}
+			else
+				{
+				const TSerialSetControlLines& lines = *(reinterpret_cast<const TSerialSetControlLines*>(aOpt.Ptr()));
+				__FLOG_2(_L8("Ioctl: Setting/clearing control lines %x/%x"), lines.iSetMask, lines.iClearMask); 
+				iComm.SetSignals(lines.iSetMask, lines.iClearMask);
+				ret = KErrNone;
+				}
+			break;
+			}
+
+		default:
+			ret = KErrNotSupported;
+			}		
+		}
+	else
+		{
+		ret = KErrNotSupported;
+		}
+		
+	
+	__FLOG_1(_L8("Ioctl completed with error %d"), ret);			
+	
+	TRequestStatus* ptrStatus = &aStatus;
+	User::RequestComplete(ptrStatus, ret);
+	}
+	
+/** Enables / Disables monitoring & link down reporting on the specified control lines
+
+@param aMask bitmaks specifying the lines to monitor, OR
+	KMonitorOff to turn monitoring off, OR
+	KConfigFailBcaSpecificOnly to set up monitoring according to Comm Role only 
+	
+@leave if the monitoring object cannot be constructed, typically due to OOM.
+*/
+void CC32Bca::MonitorControlLinesL(TUint32 aArgMask)
+	{
+	__FLOG_1(_L8("Ioctl: argument bitmask = [0x%X] "), aArgMask);	
+			
+	if(iLinkMonitor) // We may have never started...  
+			{
+			// We are called to either stop or change the monitoring options.
+			iLinkMonitor->Cancel(); // If we are not monitoring, this has no effect.
+			}
+	
+	if(KMonitorOff == aArgMask) // Stop monitoring:
+		{
+		__FLOG(_L8("MonitorControlLinesL: Stopping Control Lines monitoring."));
+		// We either never started, or we just cancelled above.
+		}
+	else // Start Monitoring, or change the monitored lines.
+		{
+		__FLOG(_L8("MonitorControlLinesL: Starting to monitor Control Lines."));	
+		
+		if(!iLinkMonitor) // We are starting to monitor for the first time 
+			{			
+			iLinkMonitor = new (ELeave)CCommLinkMonitor(*this, iComm);
+			}		
+		// At this point we have a monitoring object that isn't active.
+			
+		// A CSY does not necessarily handle the KConfigFail* correctly. For example, if 
+		// a DTR is initially low, because the terminal was not plugged in yet, we get a failure straight away,
+		// So, we translate the failure arguments and monitor the relevant lines ourselves. We fail only when a line
+		// is disasserted. This is absolutely necessary to support server-mode PPP, because we may need to wait 
+		// an arbitrary period of time for the user to plug the terminal in.
+		TUint32 lineMask(0x0);
+		if(KFailBcaSpecificOnly == aArgMask) // We decide what lines to monitor
+			{
+			// N.B. When a DTE, fail on low DSR. This is necessary to detect a disconnection on serial links that
+			// do not utilise DCD.
+			lineMask = (ECommRoleDCE == iCommRole) ? KSignalDTR : KSignalDCD | KSignalDSR;
+			}
+		else // User explicitly specified the control lines.
+			{
+			// Don't bother with sanity checks on the lines. Let C32 handle it.
+
+			if(KConfigFailCTS & aArgMask)
+				{
+				lineMask |= KSignalCTS;
+				}
+			if(KConfigFailDSR & aArgMask)
+				{
+				lineMask |= KSignalDSR;
+				}
+			if(KConfigFailDCD & aArgMask)
+				{
+				lineMask |= KSignalDCD;
+				}
+			if(KConfigFailDTR & aArgMask)
+				{
+				lineMask |= KSignalDTR;
+				}
+			if(KConfigFailRTS & aArgMask)
+				{
+				lineMask |= KSignalRTS;
+				}
+			}
+			
+		iLinkMonitor->Setup(lineMask);
+		iLinkMonitor->NotifyLinkDown();
+		
+		__FLOG(_L8("MonitorControlLinesL: Control Lines monitoring started."));	
+		}				
+	}
+
+/**
+Closes the connection to CommDB, if it is open */
+void CC32Bca::CloseCommDbConnection()
+	{
+	delete iCommsDat;
+	iCommsDat = NULL;
+	}
+
+/**
+Read Comm Port from CommDB bearer record 
+@param aPortName
+@leave if the value could not be read */
+void CC32Bca::ReadCommPortFromCommDbL(TDes& aPortName)
+	{
+	__FLOG(_L8("CC32Bca::ReadCommPortFromCommDbL()"));
+	ConnectToCommDbBearerRecordL();
+
+	TInt ret(0);
+	CMDBField<TDesC>* portField = new(ELeave) CMDBField<TDesC>(KCDTIdPortName);
+	CleanupStack::PushL(portField);
+
+	portField->SetRecordId(iModemId);
+	portField->SetMaxLengthL(KMaxTextLength);
+	TRAP(ret,portField->LoadL(*iCommsDat));
+
+	if(ret!=KErrNone)
+		{
+		__FLOG_1(_L8("portField->LoadL(*iCommsDat) left with[%d] "), ret);
+		User::Leave(ret);	
+		}
+
+	aPortName = *portField;
+	CleanupStack::PopAndDestroy(portField);	
+	}
+	
+/** 
+Read the CSY name from CommDB bearer record.
+@param aCsyName the CSY name
+@leave if the value could not be read */
+void CC32Bca::ReadCsyNameFromCommDbL(TDes& aCsyName)
+	{
+	__FLOG(_L8("CC32Bca::ReadCsyNameFromCommDbL()"));
+	ConnectToCommDbBearerRecordL();
+
+	TInt ret(0);
+	CMDBField<TDesC>* csyField = new(ELeave) CMDBField<TDesC>(KCDTIdCsyName);
+	CleanupStack::PushL(csyField);
+
+	csyField->SetRecordId(iModemId);
+	csyField->SetMaxLengthL(KMaxTextLength);
+	TRAP(ret,csyField->LoadL(*iCommsDat));
+
+	if(ret!=KErrNone)
+		{
+		__FLOG_1(_L8("csyField->LoadL(*iCommsDat) left with[%d] "), ret);
+		User::Leave(ret);	
+		}
+
+	aCsyName = *csyField;
+	CleanupStack::PopAndDestroy(csyField);
+	}
+	
+/**
+Read the specified Comm role (DTE / DCE) from CommDB bearer record
+
+@param aCommRole the specified role.
+@leave if the value could not be read */	
+void CC32Bca::ReadCommRoleFromCommDbL(TCommRole& aCommRole)
+	{
+	__FLOG(_L8("CC32Bca::ReadCommRoleFromCommDbL()"));
+	ConnectToCommDbBearerRecordL();
+	TUint32 role(0);
+
+	TInt ret(0);
+	CMDBField<TUint32>* roleField = new(ELeave) CMDBField<TUint32>(KCDTIdCommRole);
+	CleanupStack::PushL(roleField);
+
+	roleField->SetRecordId(iModemId);
+	TRAP(ret,roleField->LoadL(*iCommsDat));
+
+	if(ret!=KErrNone)
+		{
+		__FLOG_1(_L8("roleField->LoadL(*iCommsDat) left with[%d] "), ret);
+		User::Leave(ret);	
+		}
+
+	role = *roleField;
+	CleanupStack::PopAndDestroy(roleField);
+
+	aCommRole = (0 == (role & KModemCommRoleDCE)) ? ECommRoleDTE : ECommRoleDCE;
+	}
+
+/** 
+Opens a connection to the ModemBearer record specified by the provisioned IAP ID.
+
+@leave KErrNotReady, if the provisioned IAP id is invalid. System-wide error code
+       if the connection cannot be opened for some other reason.
+*/
+void CC32Bca::ConnectToCommDbBearerRecordL()
+	{
+	__FLOG(_L8("CC32Bca::ConnectToCommDbBearerRecordL()"));
+	if(iCommsDat != NULL) // CommDB is already open, we don't need to do anything
+		{
+		return;	
+		}
+	
+	if(iIapId < 1) // Can't access CommDB if IAP ID is unknown
+		{
+		__FLOG_1(_L8("iIapId[%d] is unknown"), iIapId);
+		User::Leave(KErrNotReady);	
+		}
+
+	//
+	// Open connecton to CommDB Bearer record specified by the IAP.
+	//
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+	iCommsDat = CMDBSession::NewL(KCDVersion1_2);
+#else
+	iCommsDat = CMDBSession::NewL(KCDVersion1_1);
+#endif
+	
+	CCDIAPRecord *iapRecord = static_cast<CCDIAPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
+  	CleanupStack::PushL(iapRecord);
+  	
+  	iapRecord->SetRecordId(iIapId);
+  	
+  	TBool hiddenAttributeMaskValue = iCommsDat->IsSetAttributeMask(ECDHidden);
+   	TBool privateAttributeMaskValue = iCommsDat->IsSetAttributeMask(ECDPrivate);
+  	
+  	// Check to see if viewing hidden records is enabled or not
+	if(!hiddenAttributeMaskValue || !privateAttributeMaskValue)
+		{
+		// Reveal hidden or private IAP records if a licensee has chosen to protect a record
+		// using one of these flags - the API to do this is public so internal components
+		// have to support the use of such records.
+		iCommsDat->SetAttributeMask(ECDHidden | ECDPrivate);
+		}		  	
+  	
+  	TRAPD(ret,iapRecord->LoadL(*iCommsDat));
+	if (ret != KErrNone)
+		{
+		__FLOG_1(_L8("iapRecord->LoadL(*iCommsDat) left with[%d] "), ret);
+		User::Leave(ret);
+		}    
+    
+    // If we enabled viewing hidden records now disable viewing them.
+    if(!hiddenAttributeMaskValue)
+    	{
+    	iCommsDat->ClearAttributeMask(ECDHidden);
+    	}
+ 	if(!privateAttributeMaskValue)
+		{
+		iCommsDat->ClearAttributeMask(ECDPrivate);
+		}		  	
+   	
+
+	iModemId = iapRecord->iBearer;
+	CleanupStack::PopAndDestroy(iapRecord);
+	
+	if(iModemId == 0) // ID not found.
+		{
+		__FLOG_1(_L8("iModemId[%d] is not found"), iModemId);
+		User::Leave(KErrNotFound);	
+		}
+	}
+
+
+/** Cancels an outstanding Ioctl, if any. */
+void CC32Bca::CancelIoctl()
+	{
+	__FLOG(_L8("CancelIoctl(): Ioctl cancel request. No Ioctl to cancel."));
+	}
+	
+
+/** Closes the Comm port and Comm Server.*/
+void CC32Bca::CloseCommPort()
+	{
+	__ASSERT_ALWAYS(iReader,      Panic(ENullReaderOnClose));
+	__ASSERT_ALWAYS(iWriter,     Panic(ENullWriterOnClose));
+		
+	// When we close the port, all async requests outstanding are cancelled.
+	// We must make sure nobody is waiting on them. If the underlying request is cancelled,
+	// but the owner AO is not, Cancel() on such AO hangs waiting for the request to complete.
+	
+	iReader->Cancel();
+	iWriter->Cancel();
+	if(iLinkMonitor) // Link monitor is constructed on client request only.
+		{
+		iLinkMonitor->Cancel();
+		}
+	
+	if (iCommPortOpen)
+		{
+		iComm.Close(); 
+		iCommServ.Close();	
+		iCommPortOpen = EFalse;
+		}
+	__FLOG(_L8("CloseCommPort(): Session with C32 & RComm closed."));
+	}
+
+/**
+C32Bca Panic function
+@internalComponent
+*/		
+void C32Bca::Panic(TC32BcaPanic aPanic)
+	{
+	__FLOG_STATIC2(KC32BcaLogFolder,KC32BcaLogFile,_L8("%S Panic %d"), &KC32BcaPanic(), aPanic);
+	User::Panic(KC32BcaPanic, aPanic);
+	}
+	
+
+// MC32User implementation:
+
+// Read has completed. 
+void CC32Bca::CommReadComplete(TInt aErr)
+	{
+	__ASSERT_ALWAYS(iReadRequest, Panic(ENullReadRequestStatus));
+	__ASSERT_DEBUG(KRequestPending == iReadRequest->Int(), Panic(EReadRequestNotPending));
+	
+	User::RequestComplete(iReadRequest, aErr);
+	}
+
+// Write has completed.
+void CC32Bca::CommWriteComplete(TInt aErr)
+	{
+	__ASSERT_ALWAYS(iWriteRequest, Panic(ENullWriteRequestStatus));	
+	__ASSERT_DEBUG(KRequestPending == iWriteRequest->Int(), Panic(EWriteRequestNotPending));
+	
+	User::RequestComplete(iWriteRequest, aErr);
+	}
+
+// Upcall from the link monitor: Link has gone down.	
+void CC32Bca::CommLinkDown(TInt aErr)
+	{
+	__FLOG_1(_L8("CommLinkDown: Warning: serial link has gone down with error[%d]. Erroring the outstanding Read & Write."), aErr);
+	
+	__ASSERT_DEBUG(KErrNone != aErr, Panic(EGeneralLogicError)); // If KErrNone, use has no way to know that the read has failed.
+	if(iReader->IsActive())
+		{
+		CommReadComplete(aErr);
+		iReader->Cancel();					
+		}
+	else
+		{
+		iErrorOnNextRead = aErr;
+		}
+	
+	if(iWriter->IsActive())
+		{
+		CommWriteComplete(aErr);
+		iWriter->Cancel();		
+		}
+	else
+		{
+		iErrorOnNextWrite = aErr;
+		}
+	}