usbmgmt/usbmgr/usbman/server/SRC/CUsbSession.cpp
changeset 0 c9bc50fca66e
child 6 96e575696901
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/usbman/server/SRC/CUsbSession.cpp	Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,2108 @@
+/*
+* Copyright (c) 1997-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 Session of a Symbian OS server for the RUsb API
+*
+*/
+
+/**
+ @file
+*/
+
+#include <usb/usblogger.h>
+#include "CUsbSession.h"
+#include "CUsbDevice.h"
+#include "CUsbServer.h"
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+#include "CUsbOtg.h"
+#include "cusbhost.h"
+#endif // SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+
+#include <usbstates.h>
+#include <usberrors.h>
+
+#include <usb/usbshared.h>
+#include "CPersonality.h"
+#include "rusb.h"
+#include "UsbSettings.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "USBSVR");
+#endif
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+CUsbSession* CUsbSession::iCtlSession = NULL;
+#endif // SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+
+/**
+ * Construct a Symbian OS session object.
+ *
+ * @internalComponent
+ * @param	aServer		Service the session will be a member of
+ *
+ * @return	A new CUsbSession object
+ */
+CUsbSession* CUsbSession::NewL(CUsbServer* aServer)
+	{
+	LOG_STATIC_FUNC_ENTRY
+
+	//this class has moved away from standard NewL() semantics
+	//and now uses the virtual CSession2::CreateL() function
+	//[instead of ConstructL()] which is called by CServer2
+	//and finalises the construction of the session
+	return (new (ELeave) CUsbSession(aServer));
+	}
+
+
+/**
+ * Constructor.
+ *
+ * @internalComponent
+ * @param	aServer	Service the session will be a member of
+ */
+CUsbSession::CUsbSession(CUsbServer* aServer)
+	: iUsbServer(aServer)
+	{
+	LOG_FUNC
+
+	iUsbServer->IncrementSessionCount();
+	}
+
+
+/**
+ * Destructor.
+ */
+CUsbSession::~CUsbSession()
+	{
+	LOG_FUNC
+
+	LOGTEXT2(_L8("About to Device().DeRegisterObserver(%08x"),this);
+	iUsbServer->Device().DeRegisterObserver(*this);
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+#ifndef __OVER_DUMMYUSBDI__
+	LOGTEXT2(_L8("About to Otg().DeRegisterObserver(%08x"),this);
+	iUsbServer->Otg().DeRegisterObserver(*this);
+#endif
+
+	LOGTEXT2(_L8("About to Host().DeRegisterObserver(%08x"),this);
+	iUsbServer->Host().DeregisterObserver(*this);
+
+	if ( iCtlSession && (iCtlSession == this) )
+		{
+		iCtlSession = NULL;
+		}
+#endif // SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+
+	LOGTEXT(_L8("About to iUsbServer->DecrementSessionCount()"));
+	iUsbServer->DecrementSessionCount();
+	}
+
+
+/**
+ * Called when a message is received from the client.
+ *
+ * @param	aMessage	Message received from the client
+ */
+void CUsbSession::ServiceL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	DispatchMessageL(aMessage);
+	}
+
+/**
+ * Handles 2nd Phase Construction.  Implementation of the virtual method defined in CSession2 and called from
+ * CServer2::DoConnectL() which executes when the client makes a connection request through CServer2::Connect().  If
+ * a Leave occurs at any point the CUsbSession object is cleaned up in CServer2::DoConnect().
+ */
+void CUsbSession::CreateL()
+	{
+	LOG_FUNC
+
+	// This code originally existed in the typical non-virtual ConstructL() method.
+	// However it was moved to this method for minor optimisation reasons [three less
+	// function calls and several lines less code in the NewL() method].
+
+	iPersonalityCfged = iUsbServer->Device().isPersonalityCfged();
+
+    LOGTEXT(_L8("Registering Device Observer\n"));
+	iUsbServer->Device().RegisterObserverL(*this);
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+#ifndef __OVER_DUMMYUSBDI__
+	LOGTEXT(_L8("Registering OTG Observer\n"));
+	iUsbServer->Otg().RegisterObserverL(*this);
+#endif
+
+	LOGTEXT(_L8("Registering HOST Observer\n"));
+	iUsbServer->Host().RegisterObserverL(*this);
+#endif // SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	}
+
+/**
+ * Called by CUsbDevice when the service state changes.
+ * CUsbSession is an observer of the device.
+ *
+ * @param	aLastError	The last error happened
+ * @param	aOldState	The device's service state just before it changed
+ * @param	aNewState	The device's new and current service state
+ */
+void CUsbSession::UsbServiceStateChange(TInt aLastError, TUsbServiceState aOldState,
+										TUsbServiceState aNewState)
+	{
+	LOG_FUNC
+	LOGTEXT3(_L8("    aOldState=0x%X, aNewState=0x%X"), aOldState, aNewState);
+	(void) aOldState; // a-void build warning in UREL
+
+	// Note that it's possible to have both a start and a stop outstanding!
+
+	if (iStartOutstanding)
+		{
+		HandleServiceStateChangeWhileStarting(aLastError, aNewState);
+		}
+
+	if (iStopOutstanding)
+		{
+		HandleServiceStateChangeWhileStopping(aLastError, aNewState);
+		}
+
+	// Check whether we have an observer of the service state.
+
+	if (iServiceObserverOutstanding)
+		{
+		TPckg<TUint32> pckg(aNewState);
+		iServiceObserverOutstanding = EFalse;
+		const TInt err = iServiceObserverMessage.Write(0, pckg);
+		iServiceObserverMessage.Complete(err);
+		}
+	}
+
+/**
+ * Handles a state change while a start request is currently outstanding.
+ *
+ * @param aLastError The last error happened
+ * @param aNewState The state we've moved to
+ */
+void CUsbSession::HandleServiceStateChangeWhileStarting(TInt aLastError,
+												 TUsbServiceState aNewState)
+	{
+	LOG_FUNC
+
+	switch (aNewState)
+		{
+	case EUsbServiceStarted:
+		LOGTEXT(_L8("    Completing Start successfully"));
+
+		// If the user has tried to cancel the start, they're too late!
+		if (iCancelOutstanding)
+			{
+			LOGTEXT(_L8("    Completing cancel request with KErrNone"));
+			iCancelOutstanding = EFalse;
+			iCancelMessage.Complete(KErrNone);
+			}
+
+		iStartMessage.Complete(KErrNone);
+		iStartOutstanding = EFalse;
+		break;
+
+	case EUsbServiceIdle:
+		LOGTEXT2(_L8("    Completing Start with error=%d"), aLastError);
+
+		// If there hasn't actually been an error, but we're in an unexpected
+		// state now, that means that this client cancelled the request, or
+		// another client stopped the service.
+		if (aLastError == KErrNone)
+			{
+			// If there's a cancel outstanding, then that message succeeded, but
+			// the start message should be completed with KErrCancel.
+			if (iCancelOutstanding)
+				{
+				LOGTEXT(_L8("    Completing original message with KErrCancel"));
+				iCancelOutstanding = EFalse;
+				iCancelMessage.Complete(KErrNone);
+				iStartMessage.Complete(KErrCancel);
+				}
+			else
+				{
+				iStartMessage.Complete(KErrUsbServiceStopped);
+				}
+			}
+		else
+			{
+			// There's been some kind of error, so complete the original message
+			// with the right error code.
+			if (iCancelOutstanding)
+				{
+				iCancelOutstanding = EFalse;
+				iCancelMessage.Complete(KErrNone);
+				}
+			iStartMessage.Complete(aLastError);
+			}
+
+		iStartOutstanding = EFalse;
+		break;
+
+	default:
+		break;
+		}
+	}
+
+/**
+ * Handles a state change while a stop request is currently outstanding.
+ *
+ * @param aLastError The last error happened
+ * @param aNewState The state we've moved to
+ */
+void CUsbSession::HandleServiceStateChangeWhileStopping(TInt aLastError,
+												 TUsbServiceState aNewState)
+	{
+	LOG_FUNC
+
+	switch (aNewState)
+		{
+	case EUsbServiceStarted:
+		LOGTEXT2(_L8("    Completing Stop with error=%d"), aLastError);
+
+		// If there hasn't actually been an error, but we're in an unexpected
+		// state now, that means that this client cancelled the request, or
+		// another client has started the service.
+		if (aLastError == KErrNone)
+			{
+			// If there's a cancel outstanding, then that message succeeded, but
+			// the stop message should be completed with KErrCancel.
+			if (iCancelOutstanding)
+				{
+				LOGTEXT(_L8("    Completing original message with KErrCancel"));
+				iCancelOutstanding = EFalse;
+				iCancelMessage.Complete(KErrNone);
+				iStopMessage.Complete(KErrCancel);
+				}
+			else
+				{
+				iStopMessage.Complete(KErrUsbServiceStarted);
+				}
+			}
+		else
+			{
+			// There's been some kind of error, so complete the original message
+			// with the right error code.
+			if (iCancelOutstanding)
+				{
+				iCancelOutstanding = EFalse;
+				iCancelMessage.Complete(KErrNone);
+				}
+			iStopMessage.Complete(aLastError);
+			}
+
+		iStopOutstanding = EFalse;
+		break;
+
+	case EUsbServiceIdle:
+		LOGTEXT(_L8("    Completing Stop with KErrNone"));
+
+		// If the user has tried to cancel the stop, they're too late!
+		if (iCancelOutstanding)
+			{
+			LOGTEXT(_L8("    Completing cancel request with KErrNone"));
+			iCancelOutstanding = EFalse;
+			iCancelMessage.Complete(KErrNone);
+			}
+
+		iStopMessage.Complete(KErrNone);
+		iStopOutstanding = EFalse;
+		break;
+
+	default:
+		break;
+		}
+	}
+
+/**
+ * Called by CUsbDevice when it state change. CUsbSession is an observer of
+ * the device. If the client has an Observer outstanding then complete it,
+ * otherwise put it in a circular queue.
+ *
+ * @internalComponent
+ * @param	aLastError	The last error happened
+ * @param	aOldState	The device's state just before it changed
+ * @param	aNewState	The device's new and current state
+ */
+void CUsbSession::UsbDeviceStateChange(TInt /*aLastError*/, TUsbDeviceState /*aOldState*/,
+									   TUsbDeviceState aNewState)
+	{
+	LOG_FUNC
+
+	// can we bypass the queue?
+ 	if ((iDeviceObserverOutstanding) && (iDevStateQueueHead == iDevStateQueueTail))
+		{
+		if ((iDeviceObserverMessage.Int0() & aNewState) ||
+			(aNewState == EUsbDeviceStateUndefined))
+			{
+			TPckg<TUint32> pckg(aNewState);
+
+			iNotifiedDevState = aNewState;
+
+			iDeviceObserverOutstanding = EFalse;
+			const TInt err = iDeviceObserverMessage.Write(1, pckg);
+			iDeviceObserverMessage.Complete(err);
+			}
+		}
+	else if (iObserverQueueEvents)
+		{
+		TBool addToQueue = ETrue;
+
+ 		// Search queue for similar event, truncate event queue if found
+ 		if (aNewState == EUsbDeviceStateUndefined)
+ 			{
+ 			// erase Event queue, just want this event - not interested in how we got here
+ 			iDevStateQueueTail = iDevStateQueueHead;
+
+ 			// if this is also the event mostly recently notified then don't bother to queue it
+ 			if(aNewState == iNotifiedDevState)
+ 				addToQueue = EFalse;
+ 			}
+ 		else
+ 			{
+ 			TInt queuePtr = iDevStateQueueTail;
+
+ 			// search forward from tail to head
+ 			while (queuePtr != iDevStateQueueHead)
+ 				{
+ 				if (aNewState == iDeviceStateQueue[queuePtr])
+ 					{
+ 					// Event is already queued; discard the duplicate and in-between events
+ 					LOGTEXT3(_L8("--- collapsing queue head (%d, %d)"),
+						iDevStateQueueHead,
+						(queuePtr + 1) % KDeviceStatesQueueSize);
+
+ 					// queue head moved to position following the match
+ 					iDevStateQueueHead = (queuePtr + 1) % KDeviceStatesQueueSize;
+ 					addToQueue = EFalse;
+ 					break;
+ 					}
+
+ 				// work our way through queue
+ 				queuePtr = (queuePtr + 1) % KDeviceStatesQueueSize;
+ 				}
+ 			}
+
+ 		// still want to add to queue?
+ 		if (addToQueue)
+ 			{
+ 			// add event to head of queue
+ 			iDeviceStateQueue[iDevStateQueueHead] = aNewState;
+ 			iDevStateQueueHead = (iDevStateQueueHead + 1) % KDeviceStatesQueueSize;
+ 			LOGTEXT3(_L8("+++ addqueue (%d, %d)"), iDevStateQueueHead,
+				iDevStateQueueTail);
+ 			}
+
+ 		// UsbDeviceDequeueEvent() will read from queue when RegisterObserver()
+		// is next called.
+		}
+	}
+
+/**
+ * Dequeues an event and completes the observer's request with it.
+ */
+void CUsbSession::UsbDeviceDequeueEvent()
+ 	{
+	LOG_FUNC
+
+ 	// Work our way through the queue, until we reach the end
+ 	// OR we find an event the current observer wants.
+ 	while ((iDeviceObserverOutstanding) && (iDevStateQueueHead != iDevStateQueueTail))
+ 		{
+ 		// inform the observer of state changes they are interested in AND
+ 		// if the cable is pulled out (EUsbDeviceStateUndefined)
+ 		TUsbDeviceState newState = iDeviceStateQueue[iDevStateQueueTail];
+
+ 		// advance tail towards the head
+ 		iDevStateQueueTail = (iDevStateQueueTail + 1) % KDeviceStatesQueueSize;
+
+ 		// is this state one the Observer wants?
+ 		if ((iDeviceObserverMessage.Int0() & newState) ||
+			(newState == EUsbDeviceStateUndefined))
+ 			{
+ 			TPckg<TUint32> pckg(newState);
+
+ 			iNotifiedDevState = newState;
+
+ 			LOGTEXT3(_L8(">>> dequeued event #%d (0x%x)"), iDevStateQueueTail, newState);
+
+  			iDeviceObserverOutstanding = EFalse;
+			const TInt err = iDeviceObserverMessage.Write(1, pckg);
+ 			iDeviceObserverMessage.Complete(err);
+ 			break;
+   			}
+   		}
+   	}
+
+/**
+ * Handles the request (in the form of a the message) received from the client
+ *
+ * @internalComponent
+ * @param	aMessage	The received message
+ */
+void CUsbSession::DispatchMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TBool complete = ETrue;
+	TInt ret = KErrNone;
+
+	LOGTEXT2(_L8("CUsbSession::DispatchMessageL(): func# %d"), aMessage.Function());
+
+	switch (aMessage.Function())
+		{
+	case EUsbStart:
+		ret = StartDeviceL(aMessage, complete);
+		break;
+	case EUsbStop:
+		ret = StopDeviceL(aMessage, complete);
+		break;
+	case EUsbGetCurrentState:
+		ret = GetCurrentServiceState(aMessage);
+		break;
+	case EUsbGetCurrentDeviceState:
+		ret = GetCurrentDeviceState(aMessage);
+		break;
+	case EUsbRegisterServiceObserver:
+		ret = RegisterServiceObserver(aMessage, complete);
+		break;
+	case EUsbRegisterObserver:
+		ret = RegisterDeviceObserver(aMessage, complete);
+		break;
+	case EUsbStartCancel:
+		ret = StartCancel(aMessage, complete);
+		break;
+	case EUsbStopCancel:
+		ret = StopCancel(aMessage, complete);
+		break;
+	case EUsbCancelServiceObserver:
+		ret = DeRegisterServiceObserver();
+		break;
+	case EUsbCancelObserver:
+		ret = DeRegisterDeviceObserver();
+		break;
+	case EUsbTryStart:
+		ret = TryStartDeviceL(aMessage, complete);
+		break;
+	case EUsbTryStop:
+		ret = TryStopDeviceL(aMessage, complete);
+		break;
+	case EUsbCancelInterest:
+		ret = CancelInterest(aMessage);
+		break;
+	case EUsbGetCurrentPersonalityId:
+		ret = GetCurrentPersonalityId(aMessage);
+		break;
+	case EUsbGetSupportedClasses:
+		ret = GetSupportedClasses(aMessage);
+		break;
+	case EUsbGetPersonalityIds:
+		ret = GetPersonalityIds(aMessage);
+		break;
+	case EUsbGetDescription:
+		ret = GetDescription(aMessage);
+		break;
+	case EUsbGetDetailedDescription:
+		ret = GetDetailedDescription(aMessage);
+		break;
+	case EUsbGetPersonalityProperty:
+		ret = GetPersonalityProperty(aMessage);
+		break;
+	case EUsbClassSupported:
+		ret = ClassSupported(aMessage);
+		break;
+
+#ifdef _DEBUG
+	// Heap failure debug APIs.
+
+	case EUsbDbgMarkHeap:
+		LOGTEXT(_L8("Marking heap"));
+		__UHEAP_MARK;
+		break;
+	case EUsbDbgCheckHeap:
+		LOGTEXT2(_L8("Checking heap (expecting %d cells)"), aMessage.Int0());
+		__UHEAP_CHECK(aMessage.Int0());
+		break;
+	case EUsbDbgMarkEnd:
+		LOGTEXT2(_L8("End of marking heap (expecting %d cells)"), aMessage.Int0());
+		__UHEAP_MARKENDC(aMessage.Int0());
+		break;
+	case EUsbDbgFailNext:
+		{
+		LOGTEXT2(_L8("Simulating failure after %d allocation(s)"), aMessage.Int0());
+		if (aMessage.Int0() == 0)
+			__UHEAP_RESET;
+		else
+			__UHEAP_FAILNEXT(aMessage.Int0());
+		}
+		break;
+	case EUsbDbgAlloc:
+		{
+		ret = KErrNone;
+#ifdef _DEBUG
+		LOGTEXT(_L8("\tallocate on the heap"));
+		TInt* x = NULL;
+		TRAP(ret, x = new(ELeave) TInt);
+		delete x;
+#endif // _DEBUG
+		}
+		break;
+
+#endif
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	case EUsbSetCtlSessionMode:
+		ret = SetCtlSessionMode(aMessage);
+		break;
+	case EUsbRegisterMessageObserver:
+		ret = RegisterMsgObserver(aMessage, complete);
+		break;
+	case EUsbCancelMessageObserver:
+		ret = DeRegisterMsgObserver();
+		break;
+#ifndef __OVER_DUMMYUSBDI__
+	case EUsbBusRequest:
+		ret = BusRequest();
+		break;
+	case EUsbBusRespondSrp:
+		ret = BusRespondSrp();
+		break;
+	case EUsbBusClearError:
+		ret = BusClearError();
+		break;
+	case EUsbBusDrop:
+		ret = BusDrop();
+		break;
+#else
+	case EUsbBusRequest:
+	case EUsbBusRespondSrp:
+	case EUsbBusClearError:
+	case EUsbBusDrop:
+		ret = KErrNone;
+		break;
+#endif
+	case EUsbRegisterHostObserver:
+		ret = RegisterHostObserver(aMessage, complete);
+		break;
+	case EUsbCancelHostObserver:
+		ret = DeRegisterHostObserver();
+		break;
+	case EUsbEnableFunctionDriverLoading:
+		ret = EnableFunctionDriverLoading();
+		break;
+	case EUsbDisableFunctionDriverLoading:
+		ret = DisableFunctionDriverLoading();
+		break;
+	case EUsbGetSupportedLanguages:
+		ret = GetSupportedLanguages(aMessage);
+		break;
+	case EUsbGetManufacturerStringDescriptor:
+		ret = GetManufacturerStringDescriptor(aMessage);
+		break;
+	case EUsbGetProductStringDescriptor:
+		ret = GetProductStringDescriptor(aMessage);
+		break;
+	case EUsbGetOtgDescriptor:
+		ret = GetOtgDescriptor(aMessage);
+		break;
+	case EUsbRequestSession:
+		ret = RequestSession();
+		break;
+#else // !SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	case EUsbSetCtlSessionMode:
+	case EUsbRegisterMessageObserver:
+	case EUsbCancelMessageObserver:
+	case EUsbBusRequest:
+	case EUsbBusRespondSrp:
+	case EUsbBusClearError:
+	case EUsbBusDrop:
+	case EUsbRegisterHostObserver:
+	case EUsbCancelHostObserver:
+	case EUsbEnableFunctionDriverLoading:
+	case EUsbDisableFunctionDriverLoading:
+	case EUsbGetSupportedLanguages:
+	case EUsbGetManufacturerStringDescriptor:
+	case EUsbGetProductStringDescriptor:
+	case EUsbGetOtgDescriptor:
+	case EUsbRequestSession:
+		ret = KErrNotSupported;
+		break;
+#endif // SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+
+	default:
+		LOGTEXT2(_L8("Illegal IPC argument(%d) - Panicking Client..."), aMessage.Function());
+		aMessage.Panic(KUsbCliPncCat, EUsbPanicIllegalIPC);
+		complete = EFalse;
+		break;
+		}
+
+	if (complete)
+		aMessage.Complete(ret);
+	}
+
+
+/**
+ * Client request to start the device.
+ *
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	Whether the request is complete or not
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::StartDeviceL(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	// Only 'control' session is allowed to start USB support
+	if ( !iSessionCtlMode )
+		{
+		return KErrAccessDenied;
+		}
+#endif
+
+	if (iStartOutstanding)
+		return KErrInUse;
+
+#ifndef __OVER_DUMMYUSBDI__
+
+	// If the service is idle or stopping, then we just need to start it.
+	// If it's starting (ie. by another client), then we need to perform nothing
+	// but wait for the start to complete.
+	// If it's already started, we just return immediately.
+	TUsbServiceState state = iUsbServer->Device().ServiceState();
+
+	if ((state == EUsbServiceIdle) || (state == EUsbServiceStopping))
+		{
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+		iUsbServer->Host().StartL();
+#endif
+		iUsbServer->Device().StartL();
+
+		aComplete = EFalse;
+		iStartMessage = aMessage;
+		iStartOutstanding = ETrue;
+		}
+	else if (state == EUsbServiceStarting)
+		{
+		aComplete = EFalse;
+		iStartMessage = aMessage;
+		iStartOutstanding = ETrue;
+		}
+
+	return KErrNone;
+
+#else
+	// pretend that the server is in Started state
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	iUsbServer->Host().StartL();
+#endif
+	iStartOutstanding = EFalse;
+	aMessage.IsNull();
+	aComplete = ETrue;
+	return KErrNone;
+
+#endif
+	}
+
+/**
+ * Client request to stop the device.
+ *
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	Whether the request is complete or not
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::StopDeviceL(const RMessage2& aMessage, TBool& aComplete)
+    {
+	LOG_FUNC
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	// Only 'control' session is allowed to stop USB support
+	if ( !iSessionCtlMode )
+		{
+		return KErrAccessDenied;
+		}
+#endif
+
+	if (iStopOutstanding)
+		{
+		return KErrInUse;
+		}
+
+#ifndef __OVER_DUMMYUSBDI__
+
+	// Only do anything if the service isn't currently idle. If it is, we just
+	// need to complete the user's request immediately.
+	if (iUsbServer->Device().ServiceState() != EUsbServiceIdle)
+		{
+		iUsbServer->Device().Stop();
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+		iUsbServer->Host().Stop();
+#endif
+
+		aComplete = EFalse;
+		iStopMessage = aMessage;
+		iStopOutstanding = ETrue;
+		}
+
+	return KErrNone;
+
+#else
+	// pretend that the server is in Started state
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	iUsbServer->Host().Stop();
+#endif
+	aComplete = ETrue;
+	aMessage.IsNull();
+	iStopOutstanding = EFalse;
+	return KErrNone;
+
+#endif
+    }
+
+/**
+ * Cancel the pending start operation. Note that this can just be implemented
+ * as a synchronous stop, if the start operation is pending. However, we have to
+ * retain the cancel message, so we can complete it when the stop completes.
+ *
+ * @param aMessage The message from the client
+ * @param aComplete Whether the message is complete or not
+ * @return Always KErrNone
+ */
+TInt CUsbSession::StartCancel(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	// Only 'control' session is allowed to cancel outstaning start request
+	if ( !iSessionCtlMode )
+		{
+		return KErrAccessDenied;
+		}
+#endif
+
+	if (!iStartOutstanding)
+		return KErrNone;
+
+	aComplete = EFalse;
+	iCancelMessage = aMessage;
+	iCancelOutstanding = ETrue;
+
+	if (iUsbServer->Device().ServiceState() != EUsbServiceIdle)
+		{
+		iUsbServer->Device().Stop();
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+		iUsbServer->Host().Stop();
+#endif
+		}
+
+	return KErrNone;
+	}
+
+/**
+ * Cancel the pending stop operation. Note that this can just be implemented as
+ * a synchronous start, if the stop operation is pending. However, we have to
+ * retain the cancel message, so we can complete it when the start completes.
+ *
+ * @param aMessage The message from the client
+ * @param aComplete Whether the message is complete or not
+ * @return KErrNone on success, otherwise standard error codes
+ */
+TInt CUsbSession::StopCancel(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	// Only 'control' session is allowed to cancel outstaning stop request
+	if ( !iSessionCtlMode )
+		{
+		return KErrAccessDenied;
+		}
+#endif
+
+	if (!iStopOutstanding)
+		{
+		return KErrNone;
+		}
+
+	aComplete = EFalse;
+	iCancelMessage = aMessage;
+	iCancelOutstanding = ETrue;
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	TRAPD(errHost,iUsbServer->Host().StartL());
+	if (errHost != KErrNone)
+		return errHost;
+#endif
+	TRAPD(err, iUsbServer->Device().StartL());
+	return err;
+	}
+
+/**
+ * Client request to observe the device (for state changes).
+ * Asks the device to register the session as an observer.
+ * Assures initialisation/dequeueing of Event queue.
+ *
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	set to true to complete the request
+ *
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::RegisterDeviceObserver(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+	if (iDeviceObserverOutstanding)
+		{
+		return KErrInUse;
+		}
+
+	iDeviceObserverMessage = aMessage;
+	iDeviceObserverOutstanding = ETrue;
+	aComplete = EFalse;
+
+ 	if (iObserverQueueEvents == EFalse)
+	 	{
+ 		// This is the first observer after c'tor or DeregisterObserver(),
+ 		// so zap the device event queue.
+ 		LOGTEXT(_L8("    Reset Device Event Queue"));
+ 		iDevStateQueueHead = 0;
+ 		iDevStateQueueTail = 0;
+ 		iObserverQueueEvents = ETrue;
+	 	}
+ 	else if (iDevStateQueueHead != iDevStateQueueTail)
+	 	{
+ 		// event(s) queued, we can de-queue one now
+ 		UsbDeviceDequeueEvent();
+	 	}
+
+	return KErrNone;
+	}
+
+/**
+ * Client request to observe the service (for state changes)
+ * Asks the device to register the session as an observer
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	set to true to complete the request
+ *
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::RegisterServiceObserver(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+	if (iServiceObserverOutstanding)
+		{
+		return KErrInUse;
+		}
+
+	iServiceObserverMessage = aMessage;
+	iServiceObserverOutstanding = ETrue;
+	aComplete = EFalse;
+	return KErrNone;
+	}
+
+
+/**
+ * Client request to fetch the current service state of the device
+ * Asks the device for its current service state
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ *
+ * @return	Any errors that occurred or KErrNone
+ */
+TInt CUsbSession::GetCurrentServiceState(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TUsbServiceState state = iUsbServer->Device().ServiceState();
+	LOGTEXT2(_L8("\tstate = %d"), state);
+	TPckg<TUint32> pckg(state);
+	return aMessage.Write(0, pckg);
+	}
+
+/**
+ * Client request to fetch the current device state of the device
+ * Asks the device for its current device state
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ *
+ * @return	Any errors that occurred or KErrNone
+ */
+TInt CUsbSession::GetCurrentDeviceState(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TUsbDeviceState state = iUsbServer->Device().DeviceState();
+	LOGTEXT2(_L8("\tstate = %d"), state);
+	TPckg<TUint32> pckg(state);
+	return aMessage.Write(0, pckg);
+	}
+
+
+/**
+ * Deregister the client as an observer of device state changes. Note that we don't
+ * deregister ourselves as an observer, because we need to be notified when the
+ * device state changes, so we can complete Start and Stop requests.
+ *
+ * @return Always KErrNone
+ */
+TInt CUsbSession::DeRegisterDeviceObserver()
+	{
+	LOG_FUNC
+
+	if (!iDeviceObserverOutstanding)
+		{
+		return KErrNone;
+		}
+
+	iDeviceObserverOutstanding = EFalse;
+	iDeviceObserverMessage.Complete(KErrCancel);
+
+	// client doesn't need events queuing any more
+ 	iObserverQueueEvents = EFalse;
+
+	return KErrNone;
+	}
+
+/**
+ * Deregister the client as an observer of service state changes. Note that we don't
+ * deregister ourselves as an observer, because we need to be notified when the
+ * service state changes, so we can complete Start and Stop requests.
+ *
+ * @return Always KErrNone
+ */
+TInt CUsbSession::DeRegisterServiceObserver()
+	{
+	LOG_FUNC
+
+	if (!iServiceObserverOutstanding)
+		{
+		return KErrNone;
+		}
+
+	iServiceObserverOutstanding = EFalse;
+	iServiceObserverMessage.Complete(KErrCancel);
+	return KErrNone;
+	}
+
+/**
+ * Try starting the USB device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	set to true to complete the request
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::TryStartDeviceL(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+#ifndef __OVER_DUMMYUSBDI__
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	// Only 'control' session is allowed to start USB support
+	if ( !iSessionCtlMode )
+		{
+		return KErrAccessDenied;
+		}
+#endif
+
+	if (!iPersonalityCfged)
+	{
+	return KErrNotSupported;
+	}
+
+	if (iStartOutstanding || iStopOutstanding)
+		{
+		return KErrServerBusy;
+		}
+
+	// Obtains the curent service state
+	TUsbServiceState state = iUsbServer->Device().ServiceState();
+
+
+	// USB Peripheral Stack Starting sequence:
+	// if the server is in the idle state
+	//		start it;
+	// if the server is in the started state
+	//		return KErrNone immediately;
+	// if the server is in the stopping state
+	//		return KErrServerBusy immediately;
+ 	// if the server is in the starting state
+	// (was already called by this very session in OTG/Host configuration and/or
+	//  by another session for Client Only configuration)
+	// 		if requested personality is not equal to the current one
+	//			return KErrAbort;
+	//		else
+ 	//			mark this request as outstanding and let the caller to wait
+	//			for start operation to complete;
+	if (state == EUsbServiceIdle)
+		{
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+		iUsbServer->Host().StartL();
+#endif
+		iUsbServer->Device().TryStartL(aMessage.Int0());
+		aComplete = EFalse;
+		iStartMessage = aMessage;
+		iStartOutstanding = ETrue;
+		}
+	else if (state == EUsbServiceStarting || state == EUsbServiceStarted)
+		{
+		if (aMessage.Int0() != iUsbServer->Device().CurrentPersonalityId())
+			{
+			return KErrAbort;
+			}
+
+		if (state == EUsbServiceStarting)
+			{
+			aComplete = EFalse;
+			iStartMessage = aMessage;
+			iStartOutstanding = ETrue;
+			}
+		}
+	else if (state == EUsbServiceStopping)
+		{
+		return KErrServerBusy;
+		}
+
+	return KErrNone;
+
+#else
+	// pretend that the server is in Started state
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	iUsbServer->Host().StartL();
+#endif
+	iStartOutstanding = EFalse;
+	aMessage.IsNull();
+	aComplete = ETrue;
+	return KErrNone;
+#endif
+	}
+
+/**
+ * Try stopping the USB device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	Whether the request is complete or not
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::TryStopDeviceL(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+#ifndef __OVER_DUMMYUSBDI__
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	// Only 'control' session is allowed to stop USB support
+	if ( !iSessionCtlMode )
+		{
+		return KErrAccessDenied;
+		}
+#endif
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	if (iStartOutstanding || iStopOutstanding)
+		{
+		return KErrServerBusy;
+		}
+
+	// Obtains the curent service state
+	TUsbServiceState state = iUsbServer->Device().ServiceState();
+
+	// USB Peripheral Stack Stopping sequence:
+	// if the server is in the started state
+	//		stop it;
+	// if the server is in the starting state
+	//		return KErrServerBusy immediately;
+	// if the server is in the idle state
+	//		return KErrNone immediately;
+	// if the server is in the stopping state (must by another client)
+ 	//			mark this request as outstanding and let the caller to wait
+	//			for stop operation to complete;
+	if (state == EUsbServiceStarted)
+		{
+		iUsbServer->Device().Stop();
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+		iUsbServer->Host().Stop();
+#endif
+
+		aComplete = EFalse;
+		iStopMessage = aMessage;
+		iStopOutstanding = ETrue;
+		}
+	else if (state == EUsbServiceStarting)
+		{
+		return KErrServerBusy;
+		}
+	else if (state == EUsbServiceStopping)
+		{
+		aComplete = EFalse;
+		iStopMessage = aMessage;
+		iStopOutstanding = ETrue;
+		}
+
+	return KErrNone;
+
+#else
+	// pretend that the server is in Started state
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+	iUsbServer->Host().Stop();
+#endif
+	aMessage.IsNull();
+	aComplete = ETrue;
+	iStopOutstanding = EFalse;
+	return KErrNone;
+#endif
+	}
+
+/**
+ * Cancels the interest to the outstanding request. The acutal request itself
+ * is not cancelled.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	KErrCancel
+ */
+TInt CUsbSession::CancelInterest(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	TUsbMessages toBeCancelledMsg = static_cast<TUsbMessages>(aMessage.Int0());
+	if (toBeCancelledMsg == EUsbStart || toBeCancelledMsg == EUsbTryStart)
+		{
+		if (iStartOutstanding)
+			{
+			iStartMessage.Complete(KErrNone);
+			iStartOutstanding = EFalse;
+			}
+		}
+	else if (toBeCancelledMsg == EUsbStop || toBeCancelledMsg == EUsbTryStop)
+		{
+		if (iStopOutstanding)
+			{
+			iStopMessage.Complete(KErrNone);
+			iStopOutstanding = EFalse;
+			}
+		}
+
+	return KErrCancel;
+	}
+
+/**
+ * Gets the current personality id.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetCurrentPersonalityId(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	TInt currentPersonalityId = iUsbServer->Device().CurrentPersonalityId();
+	LOGTEXT2(_L8("\tcurrentPersonalityId = %d"), currentPersonalityId);
+	TPckgC<TInt> pckg(currentPersonalityId);
+	return aMessage.Write(0, pckg);
+	}
+
+/**
+ * Gets supported classes.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	KerrTooBig if supported class > KUsbMaxSupportedClasses;
+ *          KErrNotSupported if personality is not configured
+ * 			return code from RMessage2.Write()
+ */
+TInt CUsbSession::GetSupportedClasses(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	// +1 for the size of actual class uid count
+	TInt32 classUids[KUsbMaxSupportedClasses + 1];
+	classUids[0] = 0;	// initializes class uids count to zero
+	// Gets all class uids for the given personality
+	const RPointerArray<CPersonality>&  personalities = iUsbServer->Device().Personalities();
+	TInt personalityCount = personalities.Count();
+	for (TInt i = 0; i < personalityCount; i++)
+		{
+		__ASSERT_ALWAYS(personalities[i] != NULL, _USB_PANIC(KUsbSvrPncCat, ENullPersonalityPointer));
+		if (aMessage.Int0() == personalities[i]->PersonalityId())
+			{
+			classUids[0] = personalities[i]->SupportedClasses().Count();
+			for (TInt j = 1; j <= classUids[0]; j++)
+				{
+				if (j < KUsbMaxSupportedClasses + 1)
+					{
+					classUids[j] = personalities[i]->SupportedClasses()[j - 1].iUid;
+					LOGTEXT3(_L8("\tclassUids[%d] = %d"), j, classUids[j]);
+					}
+				else
+					{
+					return KErrTooBig;
+					}
+				}
+			break;
+			}
+		}
+
+	if (classUids[0] == 0)
+		{
+		// No supported classes are found
+		return KErrNotSupported;
+		}
+
+	TInt ret;
+	HBufC8* buf = NULL;
+	TRAP(ret, buf = HBufC8::NewL((classUids[0] + 1)*sizeof(TInt32)));
+	if (ret == KErrNone)
+		{
+		TPtr8 ptr8 = buf->Des();
+		ptr8.Copy(reinterpret_cast<TUint8*>(classUids), (classUids[0] + 1)*sizeof(TInt32));
+		ret = aMessage.Write(1, ptr8);
+		}
+
+	delete buf;
+	return ret;
+	}
+
+/**
+ * Gets all personality ids.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetPersonalityIds(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	// +1 for the size of actual personality id count
+	TInt personalityIds[KUsbMaxSupportedPersonalities + 1];
+
+	const RPointerArray<CPersonality>&  personalities = iUsbServer->Device().Personalities();
+	TInt personalityCount = personalities.Count();
+	for (TInt i = 0; i < personalityCount; ++i)
+		{
+		__ASSERT_ALWAYS(personalities[i] != NULL, _USB_PANIC(KUsbSvrPncCat, ENullPersonalityPointer));
+		personalityIds[i + 1] = personalities[i]->PersonalityId();
+		}
+	personalityIds[0] = personalityCount;
+
+	TInt ret;
+	HBufC8* buf = NULL;
+	TRAP(ret, buf = HBufC8::NewL((personalityCount + 1)*sizeof(TInt)));
+	if (ret == KErrNone)
+		{
+		TPtr8 ptr8 = buf->Des();
+		ptr8.Copy(reinterpret_cast<TUint8*>(personalityIds), (personalityCount + 1)*sizeof(TInt));
+		ret = aMessage.Write(0, ptr8);
+		}
+
+	delete buf;
+	return ret;
+	}
+
+/**
+ * Gets personality description
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetDescription(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	TInt personalityId = aMessage.Int0();
+	const CPersonality* personality = iUsbServer->Device().GetPersonality(personalityId);
+	if (personality)
+		{
+		return aMessage.Write(1, *(personality->Description()));
+		}
+
+	// We should never reach here
+	return KErrNotSupported;
+	}
+
+/**
+ * Gets personality detailed description
+ *
+ * @internalComponent
+ * @param   aMessage    Message received from the client
+ * @return  Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetDetailedDescription(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+ 	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	TInt personalityId = aMessage.Int0();
+	const CPersonality* personality = iUsbServer->Device().GetPersonality(personalityId);
+    	if (personality)
+        	{
+        	if(personality->Version() < EUsbManagerResourceVersionTwo)
+            		{
+            		return KErrNotFound;
+            		}
+		return aMessage.Write(1, *(personality->DetailedDescription()));
+		}
+
+	// We should never reach here
+	return KErrNotSupported;
+	}
+
+/**
+ * Gets personality property
+ *
+ * @internalComponent
+ * @param   aMessage    Message received from the client
+ * @return  Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetPersonalityProperty(const RMessage2& aMessage)
+	{
+		LOG_FUNC
+
+		if (!iPersonalityCfged)
+			{
+			return KErrNotSupported;
+			}
+
+		TInt personalityId = aMessage.Int0();
+		const CPersonality* personality = iUsbServer->Device().GetPersonality(personalityId);
+		if (personality)
+			{
+			if(personality->Version() < EUsbManagerResourceVersionThree)
+				{
+				return KErrNotFound;
+				}
+			TPckg<TUint32> pckg(personality->Property());
+			return aMessage.Write(1, pckg);
+			}
+
+		return KErrNotSupported;
+	}
+
+/**
+ * Checks if a given class is supported by a personality.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::ClassSupported(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if (!iPersonalityCfged)
+		{
+		return KErrNotSupported;
+		}
+
+	TBool isSupported = EFalse;
+	TInt personalityId = aMessage.Int0();
+	TUid classUid = TUid::Uid(aMessage.Int1());
+	const CPersonality* personality = iUsbServer->Device().GetPersonality(personalityId);
+	if (personality)
+		{
+		isSupported = (personality->ClassSupported(classUid) != KErrNotFound);
+		TPckg<TBool> pkg2(isSupported);
+		return aMessage.Write(2, pkg2);
+		}
+
+	// We should never reach here
+	return KErrNotSupported;
+	}
+
+#ifdef SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+/**
+ * Sets or resets the control mode flag for this session.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::SetCtlSessionMode(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+
+	TBool value = (TBool)aMessage.Int0();
+	LOGTEXT2(_L8("\tSetting = %d"), static_cast<TInt>(value));
+
+	// Verify if this is the same session which set the value before
+	if ( iCtlSession && (iCtlSession != this) )
+		{
+		ret = KErrAccessDenied;
+		}
+	else
+		{
+		iSessionCtlMode = value;
+
+		// Set control session pointer if the flag is set
+		if ( iSessionCtlMode )
+			{
+			iCtlSession = this;
+			}
+		else
+			{
+			iCtlSession = NULL;
+			}
+		}
+
+	return ret;
+	}
+
+/**
+ * Asserts a request to drive VBus.
+ *
+ * @internalComponent
+ * @return	If control mode flag is not set returns KErrAccessDenied
+ * 			An error code for all other cases
+ */
+TInt CUsbSession::BusRequest()
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	if ( iSessionCtlMode )
+		{
+		ret = iUsbServer->Otg().BusRequest();
+		}
+	else
+		{
+		ret = KErrAccessDenied;
+		}
+
+	return ret;
+	}
+
+/**
+ * Asserts a request to raise VBUS but assumes this is after B-Device
+ * has used SRP to make a request to become session Host, so may be able
+ * to take some short cuts when enumerating the B-Device.
+ *
+ * @internalComponent
+ * @return	If control mode flag is not set returns KErrAccessDenied
+ * 			Any error that occurred or KErrNone for all other cases
+ */
+TInt CUsbSession::BusRespondSrp()
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	if ( iSessionCtlMode )
+		{
+		ret = iUsbServer->Otg().BusRespondSrp();
+		}
+	else
+		{
+		ret = KErrAccessDenied;
+		}
+
+	return ret;
+	}
+
+/**
+ * Clears a possible VBUS error condition (VBUS inexplicably low after
+ * having been driven)
+ *
+ * @internalComponent
+ * @return	If control mode flag is not set returns KErrAccessDenied
+ * 			Any error that occurred or KErrNone for all other cases
+ */
+TInt CUsbSession::BusClearError()
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	if ( iSessionCtlMode )
+		{
+		ret = iUsbServer->Otg().BusClearError();
+		}
+	else
+		{
+		ret = KErrAccessDenied;
+		}
+
+	return ret;
+	}
+
+/**
+ * Drops VBus.
+ *
+ * @internalComponent
+ * @return	If control mode flag is not set returns KErrAccessDenied
+ * 			Any error that occurred or KErrNone for all other cases
+ */
+TInt CUsbSession::BusDrop()
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	if ( iSessionCtlMode )
+		{
+		ret = iUsbServer->Otg().BusDrop();
+		}
+	else
+		{
+		ret = KErrAccessDenied;
+		}
+
+	return ret;
+	}
+
+/**
+ * Enables loading of Function Drivers.
+ *
+ * @internalComponent
+ * @return	If control mode flag is not set returns KErrAccessDenied
+ * 			Any error that occurred or KErrNone for all other cases
+ */
+TInt CUsbSession::EnableFunctionDriverLoading()
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	if ( iSessionCtlMode )
+		{
+		ret = iUsbServer->Host().EnableDriverLoading();
+		}
+	else
+		{
+		ret = KErrAccessDenied;
+		}
+
+	return ret;
+	}
+
+/**
+ * Disables loading of Function Drivers.
+ *
+ * @internalComponent
+ * @return	If control mode flag is not set returns KErrAccessDenied
+ * 			KErrNone for all other cases
+ */
+TInt CUsbSession::DisableFunctionDriverLoading()
+	{
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	if ( iSessionCtlMode )
+		{
+		iUsbServer->Host().DisableDriverLoading();
+		}
+	else
+		{
+		ret = KErrAccessDenied;
+		}
+
+	return ret;
+	}
+
+/**
+ * Requests an array of language identifiers supported by connected device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetSupportedLanguages(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	TRAPD(err, GetSupportedLanguagesL(aMessage));
+	return err;
+	}
+
+/**
+ * Requests an array of language identifiers supported by connected device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetSupportedLanguagesL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+
+	const TUint deviceId = aMessage.Int0();
+	LOGTEXT2(_L8("\tdeviceId = %d"), deviceId);
+
+	RArray<TUint> langIds;
+	CleanupClosePushL(langIds);
+	TInt ret = iUsbServer->Host().GetSupportedLanguages(deviceId,langIds);
+
+	if (ret == KErrNone)
+		{
+		const TUint count = langIds.Count();
+		LOGTEXT2(_L8("\tcount = %d"), count);
+
+		// Set error code if there is no languages or there are too many
+		if ( count == 0 )
+			{
+			ret = KErrNotSupported;
+			}
+		else if ( count > KUsbMaxSupportedLanguageIds )
+			{
+			ret = KErrTooBig;
+			}
+
+		if ( ret == KErrNone )
+			{
+			// Create a buffer to keep an array size and all received language Ids
+			RBuf8 buf;
+			buf.CreateL((count + 1) * sizeof(TUint));
+			CleanupClosePushL(buf);
+
+			// Save the length of the array
+			buf.Append((TUint8*)&count, sizeof(TUint));
+
+			// Save all received language Ids
+			for ( TUint ii = 0 ; ii < count; ++ii )
+				{
+				buf.Append((TUint8*)&(langIds[ii]), sizeof(TUint));
+				LOGTEXT3(_L8("Append langID[%d] = %d"),ii,langIds[ii]);
+				}
+
+			// Write back to the client.
+			ret = aMessage.Write(1, buf);
+			CleanupStack::PopAndDestroy(&buf);
+			}
+		}
+
+	CleanupStack::PopAndDestroy();
+
+	return ret;
+	}
+
+/**
+ * Requests a manufacturer string descriptor of connected device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetManufacturerStringDescriptor(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	const TUint deviceId = aMessage.Int0();
+	const TUint langId = aMessage.Int1();
+	LOGTEXT3(_L8("\tdeviceId = %d, langId = %d"), deviceId, langId);
+
+	TName string;
+	TInt ret = iUsbServer->Host().GetManufacturerStringDescriptor(deviceId,langId,string);
+	if (ret == KErrNone)
+		{
+		LOGTEXT2(_L("\tstring = \"%S\""), &string);
+		ret = aMessage.Write(2, string);
+		}
+
+	return ret;
+	}
+
+/**
+ * Requests a product string descriptor of connected device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetProductStringDescriptor(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	const TUint deviceId = aMessage.Int0();
+	const TUint langId = aMessage.Int1();
+	LOGTEXT3(_L8("\tdeviceId = %d, langId = %d"), deviceId, langId);
+
+	TName string;
+	TInt ret = iUsbServer->Host().GetProductStringDescriptor(deviceId,langId,string);
+	if (ret == KErrNone)
+		{
+		LOGTEXT2(_L("\tstring = \"%S\""), &string);
+		ret = aMessage.Write(2, string);
+		}
+
+	return ret;
+	}
+
+/**
+ * Requests a OTG descriptor of connected device.
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::GetOtgDescriptor(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	const TUint deviceId = aMessage.Int0();
+	LOGTEXT2(_L8("\tdeviceId = %d"), deviceId);
+
+    TOtgDescriptor otgDescriptor;
+	TInt ret = iUsbServer->Host().GetOtgDescriptor(deviceId, otgDescriptor);
+	if (ret == KErrNone)
+		{
+		TPckg<TOtgDescriptor> buf(otgDescriptor);
+		ret = aMessage.Write(1, buf);
+		}
+
+	return ret;
+	}
+
+/**
+ * Client request to observe the host (for state changes).
+ * Asks the host to register the session as an observer.
+ * Assures initialisation/dequeueing of Event queue.
+ * No events are queued until the first observer is registered
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	set to true to complete the request
+ *
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::RegisterHostObserver(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+	if (iHostEventObserverOutstanding)
+		{
+		return KErrInUse;
+		}
+
+	iHostEventObserverMessage = aMessage;
+	iHostEventObserverOutstanding = ETrue;
+	aComplete = EFalse;
+
+ 	if (iHostEventObserverQueueEvents == EFalse)
+	 	{
+ 		// This is the first observer after c'tor or DeregisterObserver(),
+ 		// so zap the device event queue.
+ 		LOGTEXT(_L8("    Reset OTG Host State Queue"));
+ 		iHostEventQueueHead = 0;
+ 		iHostEventQueueTail = 0;
+ 		iHostEventObserverQueueEvents = ETrue;
+	 	}
+ 	else if (iHostEventQueueHead != iHostEventQueueTail)
+	 	{
+ 		// event(s) queued, we can de-queue one now
+ 		UsbHostEventDequeue();
+	 	}
+
+	return KErrNone;
+	}
+
+/**
+ * Deregister the client as an observer of host state changes.
+ *
+ * @internalComponent
+ * @return Always KErrNone
+ */
+TInt CUsbSession::DeRegisterHostObserver()
+	{
+	LOG_FUNC
+
+
+	if (!iHostEventObserverOutstanding)
+		{
+		return KErrNone;
+		}
+
+	iHostEventObserverOutstanding = EFalse;
+	iHostEventObserverMessage.Complete(KErrCancel);
+
+	// client doesn't need events queuing any more
+ 	iHostEventObserverQueueEvents = EFalse;
+
+	return KErrNone;
+	}
+
+/**
+ * Client request to observe both OTG and HOST (for events and errors).
+ * Asks HOST and OTGDI components to register the session as an observer.
+ * Assures initialisation/dequeueing of Event queue.
+ * No events are queued until the first observer is registered
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the client
+ * @param	aComplete	set to true to complete the request
+ *
+ * @return	Any error that occurred or KErrNone
+ */
+TInt CUsbSession::RegisterMsgObserver(const RMessage2& aMessage, TBool& aComplete)
+	{
+	LOG_FUNC
+
+	if (iMsgObserverOutstanding)
+		{
+		return KErrInUse;
+		}
+
+	iMsgObserverMessage = aMessage;
+	iMsgObserverOutstanding = ETrue;
+	aComplete = EFalse;
+
+ 	if (iMsgObserverQueueEvents == EFalse)
+	 	{
+ 		// This is the first observer after c'tor or DeregisterObserver(),
+ 		// so zap the device event queue.
+ 		LOGTEXT(_L8("    Reset OTG Message Queue"));
+ 		iMsgQueueHead = 0;
+ 		iMsgQueueTail = 0;
+ 		iMsgObserverQueueEvents = ETrue;
+	 	}
+ 	else if (iMsgQueueHead != iMsgQueueTail)
+	 	{
+ 		// event(s) queued, we can de-queue one now
+ 		UsbMsgDequeue();
+	 	}
+
+	return KErrNone;
+	}
+
+/**
+ * Deregister the client as an observer of OTG/HOST events and errors.
+ *
+ * @internalComponent
+ * @return Always KErrNone
+ */
+TInt CUsbSession::DeRegisterMsgObserver()
+	{
+	LOG_FUNC
+
+	if (!iMsgObserverOutstanding)
+		{
+		return KErrNone;
+		}
+
+	iMsgObserverOutstanding = EFalse;
+	iMsgObserverMessage.Complete(KErrCancel);
+
+	// client doesn't need events queuing any more
+ 	iMsgObserverQueueEvents = EFalse;
+
+	return KErrNone;
+	}
+
+
+
+/**
+ * Called by CUsbOtg or CUsbHost when the USB OTG/HOST message has arrived
+ *
+ * @internalComponent
+ * @param aMessage The new OTG Message
+ */
+void CUsbSession::UsbOtgHostMessage(TInt aMessage)
+	{
+	LOG_FUNC
+
+	// can we bypass the queue?
+ 	if ((iMsgObserverOutstanding) && (iMsgQueueHead == iMsgQueueTail))
+		{
+		TPckg<TInt> pckg(aMessage);
+
+		iNotifiedMsg = aMessage;
+
+		iMsgObserverOutstanding = EFalse;
+		const TInt err = iMsgObserverMessage.Write(0, pckg);
+		iMsgObserverMessage.Complete(err);
+		}
+	else if (iMsgObserverQueueEvents)
+		{
+		// add event to head of queue
+		iMsgQueue[iMsgQueueHead] = aMessage;
+		iMsgQueueHead = (iMsgQueueHead + 1) % KOtgHostMessageQueueSize;
+		LOGTEXT3(_L8("+++ CUsbSession::UsbOtgMessage() addqueue (%d, %d)"), iMsgQueueHead,
+			iMsgQueueTail);
+
+ 		// UsbMsgDequeueEvent() will read from queue when RegisterMsgObserver()
+		// is next called.
+		}
+	}
+
+/**
+ * Called by CUsbHost when it state change. CUsbSession is an observer of
+ * the device. If the client has an Observer outstanding then complete it,
+ * otherwise put it in a circular queue.
+ *
+ * @internalComponent
+ * @param	aDevInfo	The information about the device being attached or detached
+ * 						along with the status of Function Driver loading
+ */
+void CUsbSession::UsbHostEvent(TDeviceEventInformation& aDevInfo)
+	{
+	LOG_FUNC
+
+	// can we bypass the queue?
+ 	if ((iHostEventObserverOutstanding) && (iHostEventQueueHead == iHostEventQueueTail))
+		{
+		iNotifiedHostState = aDevInfo;
+		iHostEventObserverOutstanding = EFalse;
+
+		LOGTEXT(_L8("CUsbSession::UsbHostEvent() detected outstanding request"));
+
+		TPckg<TDeviceEventInformation> info(aDevInfo);
+		const TInt err = iHostEventObserverMessage.Write(0, info);
+		iHostEventObserverMessage.Complete(err);
+		LOGTEXT2(_L8("CUsbSession::UsbHostEvent() detects outstanding request: request is compeleted with %d"), err);
+		}
+	else if (iHostEventObserverQueueEvents)
+		{
+		// add dev info to head of queue
+		iHostStateQueue[iHostEventQueueHead] = aDevInfo;
+		iHostEventQueueHead = (iHostEventQueueHead + 1) % KDeviceStatesQueueSize;
+		LOGTEXT3(_L8("+++ CUsbSession::UsbHostEvent() addqueue (%d, %d)"), iHostEventQueueHead,
+			iHostEventQueueTail);
+
+ 		// UsbHostStateDequeueEvent() will read from queue when RegisterHostObserver()
+		// is next called.
+		}
+	}
+
+/**
+ * Dequeues an event and completes the observer's request with it.
+ */
+void CUsbSession::UsbMsgDequeue()
+ 	{
+	LOG_FUNC
+
+	// Work our way through the queue, until we reach the end
+ 	// OR we find an event the current observer wants.
+ 	if ((iMsgObserverOutstanding) && (iMsgQueueHead != iMsgQueueTail))
+ 		{
+ 		TInt newMsg = iMsgQueue[iMsgQueueTail];
+
+ 		// advance tail towards the head
+ 		iMsgQueueTail = (iMsgQueueTail + 1) % KOtgHostMessageQueueSize;
+
+ 		TPckg<TUint32> pckg(newMsg);
+ 		iNotifiedMsg = newMsg;
+
+ 		LOGTEXT3(_L8(">>> dequeued event #%d (0x%x)"), iMsgQueueTail, newMsg);
+
+		iMsgObserverOutstanding = EFalse;
+		const TInt err = iMsgObserverMessage.Write(0, pckg);
+		iMsgObserverMessage.Complete(err);
+   		}
+  	}
+
+/**
+ * Dequeues an event and completes the observer's request with it.
+ */
+void CUsbSession::UsbHostEventDequeue()
+ 	{
+	LOG_FUNC
+
+	// Work our way through the queue, until we reach the end
+ 	// OR we find an event the current observer wants.
+ 	if ((iHostEventObserverOutstanding) && (iHostEventQueueHead != iHostEventQueueTail))
+ 		{
+ 		// inform the observer of state changes they are interested in AND
+ 		// if the cable is pulled out (EUsbDeviceStateUndefined)
+ 		TDeviceEventInformation newDevInfo = iHostStateQueue[iHostEventQueueTail];
+		iNotifiedHostState = newDevInfo;
+
+ 		// advance tail towards the head
+ 		iHostEventQueueTail = (iHostEventQueueTail + 1) % KDeviceStatesQueueSize;
+
+		LOGTEXT3(_L8(">>> CUsbSession::UsbHostStateDequeueEvent() dequeued event #%d (0x%x)"), iHostEventQueueTail, newDevInfo.iEventType);
+
+		TPckg<TDeviceEventInformation> info(newDevInfo);
+		iHostEventObserverOutstanding = EFalse;
+		const TInt err = iHostEventObserverMessage.Write(0, info);
+		iHostEventObserverMessage.Complete(err);
+
+		LOGTEXT2(_L8("CUsbSession::UsbHostStateDequeueEvent() detects outstanding request: request is compeleted with %d"), err);
+   		}
+   	}
+
+TInt CUsbSession::RequestSession()
+	{
+	return DoRequestSession();
+	}
+
+TInt CUsbSession::DoRequestSession()
+	{
+	if ( iCtlSession )
+		{
+		if ( iCtlSession == this )
+			{
+	 		if (iMsgObserverQueueEvents)
+	 			{
+	 			UsbOtgHostMessage(KUsbMessageRequestSession);
+	 			return KErrNone;
+	 			}
+		 	else
+		 		{
+		 		return KErrNotFound;
+		 		}
+			}
+		else
+			{
+			return iCtlSession->DoRequestSession();
+			}
+		}
+ 	return KErrNotFound;
+	}
+
+#endif // SYMBIAN_ENABLE_USB_OTG_HOST_PRIV
+