usbmgmt/usbmgr/usbman/server/SRC/CUsbDevice.cpp
changeset 0 c9bc50fca66e
child 21 d67598c1c3be
child 42 f92a4f87e424
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/usbman/server/SRC/CUsbDevice.cpp	Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,1555 @@
+/*
+* 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 the main object of Usbman that manages all the USB Classes
+* and the USB Logical Device (via CUsbDeviceStateWatcher).
+*
+*/
+
+/**
+ @file
+*/
+
+#include "CUsbDevice.h"
+#include "CUsbDeviceStateWatcher.h"
+#include <cusbclasscontrolleriterator.h>
+#include "MUsbDeviceNotify.h"
+#include "UsbSettings.h"
+#include "CUsbServer.h"
+#include <cusbclasscontrollerbase.h>
+#include <cusbclasscontrollerplugin.h>
+#include "UsbUtils.h"
+#include <cusbmanextensionplugin.h>
+
+#ifdef USE_DUMMY_CLASS_CONTROLLER
+#include "CUsbDummyClassController.h"
+#endif
+
+#include <bafl/sysutil.h>
+#include <usb/usblogger.h>
+#include <e32svr.h>
+#include <e32base.h>
+#include <e32std.h>
+#include <usbman.rsg>
+#include <f32file.h>
+#include <barsc.h>
+#include <barsread.h>
+#include <bautils.h>
+#include <e32property.h> //Publish & Subscribe header
+#include "CPersonality.h"
+
+_LIT(KUsbLDDName, "eusbc"); //Name used in call to User::LoadLogicalDevice
+_LIT(KUsbLDDFreeName, "Usbc"); //Name used in call to User::FreeLogicalDevice
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "USBSVR");
+#endif
+
+// Panic category only used in debug builds
+#ifdef _DEBUG
+_LIT(KUsbDevicePanicCategory, "UsbDevice");
+#endif
+
+/**
+ * Panic codes for the USB Device Class
+ */
+enum TUsbDevicePanic
+	{
+	/** Class called while in an illegal state */
+	EBadAsynchronousCall = 0,
+	EConfigurationError,
+	EResourceFileNotFound,
+	/** ConvertUidsL called with an array that is not empty */
+	EUidArrayNotEmpty,
+	};
+
+
+CUsbDevice* CUsbDevice::NewL(CUsbServer& aUsbServer)
+/**
+ * Constructs a CUsbDevice object.
+ *
+ * @return	A new CUsbDevice object
+ */
+	{
+	LOG_STATIC_FUNC_ENTRY
+
+	CUsbDevice* r = new (ELeave) CUsbDevice(aUsbServer);
+	CleanupStack::PushL(r);
+	r->ConstructL();
+	CleanupStack::Pop(r);
+	return r;
+	}
+
+
+CUsbDevice::~CUsbDevice()
+/**
+ * Destructor.
+ */
+	{
+	LOG_FUNC
+
+	// Cancel any outstanding asynchronous operation.
+	Cancel();
+	
+	delete iUsbClassControllerIterator;
+	iSupportedClasses.ResetAndDestroy();
+	iSupportedPersonalities.ResetAndDestroy();
+	iSupportedClassUids.Close();
+
+	iExtensionPlugins.ResetAndDestroy();
+
+	if(iEcom)
+		iEcom->Close();
+	REComSession::FinalClose();
+
+	// Free any memory allocated to the list of observers. Note that
+	// we don't want to call ResetAndDestroy, because we don't own
+	// the observers themselves.
+	iObservers.Reset();
+
+#ifndef __WINS__
+	LOGTEXT2(_L8("about to delete device state watcher @ %08x"), (TUint32) iDeviceStateWatcher);
+	delete iDeviceStateWatcher;
+	LOGTEXT(_L8("deleted device state watcher"));
+
+	iLdd.Close();
+
+	LOGTEXT(_L8("Freeing logical device"));
+	TInt err = User::FreeLogicalDevice(KUsbLDDFreeName);
+	//Putting the LOGTEXT2 inside the if statement prevents a compiler
+	//warning about err being unused in UREL builds.
+	if(err)
+		{
+		LOGTEXT2(_L8("     User::FreeLogicalDevice returned %d"),err);
+		}
+#endif	
+
+	delete iDefaultSerialNumber;
+	}
+
+
+CUsbDevice::CUsbDevice(CUsbServer& aUsbServer)
+	: CActive(EPriorityStandard)
+	, iDeviceState(EUsbDeviceStateUndefined)
+	, iServiceState(EUsbServiceIdle)
+	, iUsbServer(aUsbServer)
+	, iPersonalityCfged(EFalse)
+/**
+ * Constructor.
+ */
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+void CUsbDevice::ConstructL()
+/**
+ * Performs 2nd phase construction of the USB device.
+ */
+	{
+	LOG_FUNC
+	
+	iEcom = &(REComSession::OpenL());
+
+	iUsbClassControllerIterator = new(ELeave) CUsbClassControllerIterator(iSupportedClasses);
+
+#ifndef __WINS__
+	LOGTEXT(_L8("About to load LDD"));
+	TInt err = User::LoadLogicalDevice(KUsbLDDName);
+
+	if (err != KErrNone && err != KErrAlreadyExists)
+		{
+		LEAVEL(err);
+		}
+
+	LOGTEXT(_L8("About to open LDD"));
+	LEAVEIFERRORL(iLdd.Open(0));
+	LOGTEXT(_L8("LDD opened"));
+	
+	// hide bus from host while interfaces are being set up
+	iLdd.DeviceDisconnectFromHost();
+
+	// Does the USC support cable detection while powered off? If no, then 
+	// call PowerUpUdc when RUsb::Start finishes, as is obvious. If yes, we 
+	// delay calling PowerUpUdc until both the service state is 'started' and 
+	// the device state is not undefined. This is to save power in the UDC 
+	// when there's no point it being powered.
+	TUsbDeviceCaps devCapsBuf;
+	LEAVEIFERRORL(iLdd.DeviceCaps(devCapsBuf));
+	if ( devCapsBuf().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower )
+		{
+		LOGTEXT(_L8("\tUDC supports cable detect when unpowered"));
+		iUdcSupportsCableDetectWhenUnpowered = ETrue;
+		}
+	else
+		{
+		LOGTEXT(_L8("\tUDC does not support cable detect when unpowered"));
+		}
+
+	TUsbcDeviceState deviceState;
+	LEAVEIFERRORL(iLdd.DeviceStatus(deviceState));
+	SetDeviceState(deviceState);
+	LOGTEXT(_L8("Got device state"));
+
+	iDeviceStateWatcher = CUsbDeviceStateWatcher::NewL(*this, iLdd);
+	iDeviceStateWatcher->Start();
+
+	// Get hold of the default serial number in the driver
+	// This is so it can be put back in place when a device that sets a
+	// different serial number (through the P&S key) is stopped
+	iDefaultSerialNumber = HBufC16::NewL(KUsbStringDescStringMaxSize);
+	TPtr16 serNum = iDefaultSerialNumber->Des();
+	err = iLdd.GetSerialNumberStringDescriptor(serNum);
+	if (err == KErrNotFound)
+		{
+		delete iDefaultSerialNumber;
+		iDefaultSerialNumber = NULL;
+		LOGTEXT(_L8("No default serial number"));
+		}
+	else
+		{
+		LEAVEIFERRORL(err);
+#ifdef __FLOG_ACTIVE
+		TBuf8<KUsbStringDescStringMaxSize> narrowString;
+		narrowString.Copy(serNum);
+		LOGTEXT2(_L8("Got default serial number %S"), &narrowString);
+#endif //__FLOG_ACTIVE		
+		}
+
+	LOGTEXT(_L8("UsbDevice::ConstructL() finished"));
+#endif
+	
+#ifndef __OVER_DUMMYUSBDI__
+	InstantiateExtensionPluginsL();
+#endif
+	}
+
+void CUsbDevice::InstantiateExtensionPluginsL()
+	{
+	LOGTEXT(_L8(">>CUsbDevice::InstantiateExtensionPluginsL"));
+	const TUid KUidExtensionPluginInterface = TUid::Uid(KUsbmanExtensionPluginInterfaceUid);
+	RImplInfoPtrArray implementations;
+	const TEComResolverParams noResolverParams;
+	REComSession::ListImplementationsL(KUidExtensionPluginInterface, noResolverParams, KRomOnlyResolverUid, implementations);
+	CleanupResetAndDestroyPushL(implementations);
+	LOGTEXT2(_L8("Number of implementations of extension plugin interface: %d"), implementations.Count());
+
+	for (TInt i=0; i<implementations.Count(); i++)
+		{
+		CUsbmanExtensionPlugin* plugin = CUsbmanExtensionPlugin::NewL(implementations[i]->ImplementationUid(), *this);
+		CleanupStack::PushL(plugin);
+		iExtensionPlugins.AppendL(plugin); // transfer ownership to iExtensionPlugins
+		CleanupStack::Pop(plugin);
+		LOGTEXT2(_L8("Added extension plugin with UID 0x%08x"),
+			implementations[i]->ImplementationUid());
+		}
+
+	CleanupStack::PopAndDestroy(&implementations);
+
+	LOGTEXT(_L8("<<CUsbDevice::InstantiateExtensionPluginsL"));
+	}
+
+
+	
+   	
+void CUsbDevice::EnumerateClassControllersL()
+/**
+ * Loads all USB class controllers at startup.
+ *
+ */
+	{
+	LOG_FUNC
+	
+#ifdef USE_DUMMY_CLASS_CONTROLLER
+	//create a TLinearOrder to supply the comparison function, Compare(), to be used  
+	//to determine the order to add class controllers
+	TLinearOrder<CUsbClassControllerBase> order(CUsbClassControllerBase::Compare);
+	
+	// For GT171 automated tests, create three instances of the dummy class 
+	// controller, which will read their behaviour from an ini file. Do not 
+	// make any other class controllers.
+	for ( TUint ii = 0 ; ii < 3 ; ii++ )
+		{
+		AddClassControllerL(CUsbDummyClassController::NewL(*this, ii), order);	
+		}
+	    
+	LEAVEIFERRORL(iUsbClassControllerIterator->First());
+	    
+#else
+
+	// Add a class controller statically.
+	// The next line shows how to add a class controller, CUsbExampleClassController,
+	// statically
+
+	// AddClassControllerL(CUsbExampleClassController::NewL(*this),order);
+	
+	// Load class controller plug-ins
+
+	RImplInfoPtrArray implementations;
+
+	const TEComResolverParams noResolverParams;
+	REComSession::ListImplementationsL(KUidUsbPlugIns, noResolverParams, KRomOnlyResolverUid, implementations);
+  	CleanupResetAndDestroyPushL(implementations);
+  	
+	LOGTEXT2(_L8("Number of implementations to load  %d"), implementations.Count());
+	
+	for (TInt i=0; i<implementations.Count(); i++)
+		{
+		LOGTEXT2(_L8("Adding class controller with UID %x"),
+			implementations[i]->ImplementationUid());
+		const TUid uid = implementations[i]->ImplementationUid();
+		LEAVEIFERRORL(iSupportedClassUids.Append(uid));
+		}	
+			
+	CleanupStack::PopAndDestroy(&implementations);
+	
+#endif // USE_DUMMY_CLASS_CONTROLLER
+	}
+
+void CUsbDevice::AddClassControllerL(CUsbClassControllerBase* aClassController, 
+									TLinearOrder<CUsbClassControllerBase> aOrder)
+/**
+ * Adds a USB class controller to the device. The controller will now be
+ * managed by this device. Note that the class controller, aClassController, is now
+ * owned by this function and can be destroyed by it.  Calling functions do not need to 
+ * destroy the class controller. 
+ *
+ * @param	aClassController	Class to be managed
+ * @param   aOrder              Specifies order CUsbClassControllerBase objects are to be
+ *                              added
+ */
+	{
+	LOG_FUNC
+	
+	
+	TInt rc = KErrNone;	
+	
+	if(isPersonalityCfged()) // do not take into account priorities
+		{
+		rc = iSupportedClasses.Append(aClassController);	
+		}
+	else
+		{
+		rc = iSupportedClasses.InsertInOrderAllowRepeats(
+		aClassController, aOrder);
+		} 
+		
+	if (rc != KErrNone) 
+		{
+		// Avoid memory leak by deleting class controller if the append fails.
+		delete aClassController;
+		LEAVEL(rc);
+		}
+	}
+
+void CUsbDevice::RegisterObserverL(MUsbDeviceNotify& aObserver)
+/**
+ * Register an observer of the device.
+ * Presently, the device supports watching state.
+ *
+ * @param	aObserver	New Observer of the device
+ */
+	{
+	LOG_FUNC
+
+	LEAVEIFERRORL(iObservers.Append(&aObserver));
+	}
+
+
+void CUsbDevice::DeRegisterObserver(MUsbDeviceNotify& aObserver)
+/**
+ * De-registers an existing device observer.
+ *
+ * @param	aObserver	The existing device observer to be de-registered
+ */
+	{
+	LOG_FUNC
+
+	TInt index = iObservers.Find(&aObserver);
+
+	if (index >= 0)
+		iObservers.Remove(index);
+	}
+
+
+void CUsbDevice::StartL()
+/**
+ * Start the USB Device and all its associated USB classes.
+ * Reports errors and state changes via observer interface.
+ */
+	{
+	LOG_FUNC
+
+	Cancel();
+	SetServiceState(EUsbServiceStarting);
+
+	TRAPD(err, SetDeviceDescriptorL());
+	if ( err != KErrNone )
+		{
+		SetServiceState(EUsbServiceIdle);
+		LEAVEL(err);		
+		}
+
+	iLastError = KErrNone;
+	StartCurrentClassController();
+	}
+
+void CUsbDevice::Stop()
+/**
+ * Stop the USB device and all its associated USB classes.
+ */
+	{
+	LOG_FUNC
+
+	Cancel();
+	SetServiceState(EUsbServiceStopping);
+	
+	iLastError = KErrNone;
+	StopCurrentClassController();
+	}
+
+void CUsbDevice::SetServiceState(TUsbServiceState aState)
+/**
+ * Change the device's state and report the change to the observers.
+ *
+ * @param	aState	New state that the device is moving to
+ */
+	{
+	LOGTEXT3(_L8("Calling: CUsbDevice::SetServiceState [iServiceState=%d,aState=%d]"),
+		iServiceState, aState);
+
+	if (iServiceState != aState)
+		{
+		// Change state straight away in case any of the clients check it
+		TUsbServiceState oldState = iServiceState;
+		iServiceState = aState;
+		TUint length = iObservers.Count();
+
+		for (TUint i = 0; i < length; i++)
+			{
+			iObservers[i]->UsbServiceStateChange(LastError(), oldState,
+				iServiceState);
+			}
+
+		if (iServiceState == EUsbServiceIdle)
+			iUsbServer.LaunchShutdownTimerIfNoSessions();
+		}
+	LOGTEXT(_L8("Exiting: CUsbDevice::SetServiceState"));
+	}
+
+void CUsbDevice::SetDeviceState(TUsbcDeviceState aState)
+/**
+ * The CUsbDevice::SetDeviceState method
+ *
+ * Change the device's state and report the change to the observers
+ *
+ * @internalComponent
+ * @param	aState	New state that the device is moving to
+ */
+	{
+	LOG_FUNC
+	LOGTEXT3(_L8("\taState = %d, iDeviceState = %d"), aState, iDeviceState);
+
+	TUsbDeviceState state;
+	switch (aState)
+		{
+	case EUsbcDeviceStateUndefined:
+		state = EUsbDeviceStateUndefined;
+		break;
+	case EUsbcDeviceStateAttached:
+		state = EUsbDeviceStateAttached;
+		break;
+	case EUsbcDeviceStatePowered:
+		state = EUsbDeviceStatePowered;
+		break;
+	case EUsbcDeviceStateDefault:
+		state = EUsbDeviceStateDefault;
+		break;
+	case EUsbcDeviceStateAddress:
+		state = EUsbDeviceStateAddress;
+		break;
+	case EUsbcDeviceStateConfigured:
+		state = EUsbDeviceStateConfigured;
+		break;
+	case EUsbcDeviceStateSuspended:
+		state = EUsbDeviceStateSuspended;
+		break;
+	default:
+		return;
+		}
+
+	if (iDeviceState != state)
+		{
+#ifndef __WINS__
+		if (iDeviceState == EUsbDeviceStateUndefined &&
+			iUdcSupportsCableDetectWhenUnpowered &&
+			iServiceState == EUsbServiceStarted)
+			{
+			// We just changed state away from undefined. Hence the cable must
+			// now be attached (if it wasn't before). If the UDC supports
+			// cable detection when unpowered, NOW is the right time to power
+			// it up (so long as usbman is fully started).
+			(void)PowerUpAndConnect(); // We don't care about any errors here.
+			}
+#endif // __WINS__
+		// Change state straight away in case any of the clients check it
+		TUsbDeviceState oldState = iDeviceState;
+		iDeviceState = state;
+		TUint length = iObservers.Count();
+
+		for (TUint i = 0; i < length; i++)
+			{
+			iObservers[i]->UsbDeviceStateChange(LastError(), oldState, iDeviceState);
+			}
+		}
+	}
+
+/**
+ * Callback called by CDeviceHandler when the USB bus has sucessfully
+ * completed a ReEnumeration (restarted all services).
+ */
+void CUsbDevice::BusEnumerationCompleted()
+	{
+	LOG_FUNC
+
+	// Has the start been cancelled?
+	if (iServiceState == EUsbServiceStarting)
+		{
+		SetServiceState(EUsbServiceStarted);
+		}
+	else
+		{
+		LOGTEXT(_L8("    Start has been cancelled!"));
+		}
+	}
+
+void CUsbDevice::BusEnumerationFailed(TInt aError)
+/**
+ * Callback called by CDeviceHandler when the USB bus has
+ * completed an ReEnumeration (Restarted all services) with errors
+ *
+ * @param	aError	Error that has occurred during Re-enumeration
+ */
+	{
+	LOGTEXT2(_L8("CUsbDevice::BusEnumerationFailed [aError=%d]"), aError);
+	iLastError = aError;
+
+	if (iServiceState == EUsbServiceStarting)
+		{
+		SetServiceState(EUsbServiceStopping);
+		StopCurrentClassController();
+		}
+	else
+		{
+		LOGTEXT(_L8("    Start has been cancelled!"));
+		}
+	}
+
+
+void CUsbDevice::StartCurrentClassController()
+/**
+ * Called numerous times to start all the USB classes.
+ */
+	{
+	LOG_FUNC
+
+	iUsbClassControllerIterator->Current()->Start(iStatus);
+	SetActive();
+	}
+
+void CUsbDevice::StopCurrentClassController()
+/**
+ * Called numerous times to stop all the USB classes.
+ */
+	{
+	LOG_FUNC
+
+	iUsbClassControllerIterator->Current()->Stop(iStatus);
+	SetActive();
+	}
+
+/**
+Utility function to power up the UDC and connect the
+device to the host.
+*/
+TInt CUsbDevice::PowerUpAndConnect()
+	{
+	LOG_FUNC
+	LOGTEXT(_L8("\tPowering up UDC..."));
+	TInt res = iLdd.PowerUpUdc();
+	LOGTEXT2(_L8("\tPowerUpUdc res = %d"), res);
+	res = iLdd.DeviceConnectToHost();
+	LOGTEXT2(_L8("\tDeviceConnectToHost res = %d"), res);
+	return res;
+	}
+
+void CUsbDevice::RunL()
+/**
+ * Called when starting or stopping a USB class has completed, successfully or
+ * otherwise. Continues with the process of starting or stopping until all
+ * classes have been completed.
+ */
+	{
+	LOGTEXT2(_L8(">>CUsbDevice::RunL [iStatus=%d]"), iStatus.Int());
+
+	LEAVEIFERRORL(iStatus.Int());
+
+	switch (iServiceState)
+		{
+	case EUsbServiceStarting:
+		if (iUsbClassControllerIterator->Next() == KErrNotFound)
+			{
+#ifndef __WINS__
+			if (!iUdcSupportsCableDetectWhenUnpowered || iDeviceState != EUsbDeviceStateUndefined)
+				{
+				// We've finished starting the classes. We can just power up the UDC
+				// now: there's no need to re-enumerate, because we soft disconnected
+				// earlier. This will also do a soft connect.
+				LOGTEXT(_L8("Finished starting classes: powering up UDC"));
+
+				// It isn't an error if this call fails. This will happen, for example,
+				// in the case where there are no USB classes defined.
+				(void)PowerUpAndConnect();
+				}
+#endif
+			// If we're not running on target, we can just go to "started".
+			SetServiceState(EUsbServiceStarted);
+			}
+		else
+			{
+			StartCurrentClassController();
+			}
+		break;
+
+	case EUsbServiceStopping:
+		if (iUsbClassControllerIterator->Previous() == KErrNotFound)
+			{
+			// if stopping classes, hide the USB interface from the host
+#ifndef __WINS__
+			iLdd.DeviceDisconnectFromHost();
+
+			// Restore the default serial number 
+			if (iDefaultSerialNumber)
+				{
+				TInt res = iLdd.SetSerialNumberStringDescriptor(*iDefaultSerialNumber);
+				LOGTEXT2(_L8("Restore default serial number res = %d"), res);
+				}
+			else
+				{
+				TInt res = iLdd.RemoveSerialNumberStringDescriptor();
+				LOGTEXT2(_L8("Remove serial number res = %d"), res);
+				}
+				
+#endif			
+			SetServiceState(EUsbServiceIdle);
+			}
+		else
+			{
+			StopCurrentClassController();
+			}
+		break;
+
+	default:
+		__ASSERT_DEBUG( EFalse, _USB_PANIC(KUsbDevicePanicCategory, EBadAsynchronousCall) );
+		break;
+		}
+	LOGTEXT(_L8("<<CUsbDevice::RunL"));
+	}
+
+void CUsbDevice::DoCancel()
+/**
+ * Standard active object cancellation function. If we're starting or stopping
+ * a USB class, cancels it. If we're not, then we shouldn't be active and hence
+ * this function being called is a programming error.
+ */
+	{
+	LOG_FUNC
+
+	switch (iServiceState)
+		{
+	case EUsbServiceStarting:
+	case EUsbServiceStopping:
+		iUsbClassControllerIterator->Current()->Cancel();
+		break;
+
+	default:
+		__ASSERT_DEBUG( EFalse, _USB_PANIC(KUsbDevicePanicCategory, EBadAsynchronousCall) );
+		break;
+		}
+	}
+
+TInt CUsbDevice::RunError(TInt aError)
+/**
+ * Standard active object RunError function. Handles errors which occur when
+ * starting and stopping the USB class objects.
+ *
+ * @param aError The error which occurred
+ * @return Always KErrNone, to avoid an active scheduler panic
+ */
+	{
+	LOGTEXT2(_L8("CUsbDevice::RunError [aError=%d]"), aError);
+
+	iLastError = aError;
+
+	switch (iServiceState)
+		{
+	case EUsbServiceStarting:
+	case EUsbServiceStarted:
+		// An error has happened while we're either started or starting, so
+		// we have to stop all the classes which were successfully started.
+		if ((iUsbClassControllerIterator->Current()->State() ==
+				EUsbServiceIdle) &&
+			(iUsbClassControllerIterator->Previous() == KErrNotFound))
+			{
+			SetServiceState(EUsbServiceIdle);
+			}
+		else
+			{
+			SetServiceState(EUsbServiceStopping);
+			StopCurrentClassController();
+			}
+		break;
+
+	case EUsbServiceStopping:
+		// Argh, we've got problems. Let's stop as many classes as we can.
+		if (iUsbClassControllerIterator->Previous() == KErrNotFound)
+			SetServiceState(EUsbServiceIdle);
+		else
+			StopCurrentClassController();
+		break;
+
+	default:
+		__ASSERT_DEBUG( EFalse, _USB_PANIC(KUsbDevicePanicCategory, EBadAsynchronousCall) );
+		break;
+		}
+
+	return KErrNone;
+	}
+
+CUsbClassControllerIterator* CUsbDevice::UccnGetClassControllerIteratorL()
+/**
+ * Function used by USB classes to get an iterator over the set of classes
+ * owned by this device. Note that the caller takes ownership of the iterator
+ * which this function returns.
+ *
+ * @return A new iterator
+ */
+	{
+	LOG_FUNC
+
+	return new (ELeave) CUsbClassControllerIterator(iSupportedClasses);
+	}
+
+void CUsbDevice::UccnError(TInt aError)
+/**
+ * Function called by USB classes to notify the device of a fatal error. In
+ * this situation, we should just stop all the classes we can.
+ *
+ * @param aError The error that's occurred
+ */
+	{
+	LOG_FUNC
+
+	RunError(aError);
+	}
+
+
+#ifdef __FLOG_ACTIVE
+void CUsbDevice::PrintDescriptor(CUsbDevice::TUsbDeviceDescriptor& aDeviceDescriptor)
+	{
+	LOGTEXT2(_L8("\tiLength is %d"), aDeviceDescriptor.iLength);
+	LOGTEXT2(_L8("\tiDescriptorType is %d"), aDeviceDescriptor.iDescriptorType);
+	LOGTEXT2(_L8("\tBcdUsb is: 0x%04x"), aDeviceDescriptor.iBcdUsb);
+	LOGTEXT2(_L8("\tDeviceClass is: 0x%02x"), aDeviceDescriptor.iDeviceClass);
+	LOGTEXT2(_L8("\tDeviceSubClass is: 0x%02x"), aDeviceDescriptor.iDeviceSubClass);
+	LOGTEXT2(_L8("\tDeviceProtocol is: 0x%02x"), aDeviceDescriptor.iDeviceProtocol);
+	LOGTEXT2(_L8("\tiMaxPacketSize is: 0x%02x"), aDeviceDescriptor.iMaxPacketSize);
+	
+	LOGTEXT2(_L8("\tVendorId is: 0x%04x"), aDeviceDescriptor.iIdVendor);
+	LOGTEXT2(_L8("\tProductId is: 0x%04x"), aDeviceDescriptor.iIdProduct);
+	LOGTEXT2(_L8("\tBcdDevice is: 0x%04x"), aDeviceDescriptor.iBcdDevice);
+
+	LOGTEXT2(_L8("\tiManufacturer is: 0x%04x"), aDeviceDescriptor.iManufacturer);
+	LOGTEXT2(_L8("\tiSerialNumber is: 0x%04x"), aDeviceDescriptor.iSerialNumber);
+	LOGTEXT2(_L8("\tiNumConfigurations is: 0x%04x"), aDeviceDescriptor.iNumConfigurations);
+	}
+#endif
+//
+void CUsbDevice::SetDeviceDescriptorL()
+/**
+ * Modifies the USB device descriptor.
+ */
+	{
+	LOG_FUNC
+
+#ifndef __WINS__
+
+	TInt desSize = 0;
+	iLdd.GetDeviceDescriptorSize(desSize);
+	LOGTEXT2(_L8("UDeviceDescriptorSize = %d"), desSize);
+	HBufC8* deviceBuf = HBufC8::NewLC(desSize);
+	TPtr8   devicePtr = deviceBuf->Des();
+	devicePtr.SetLength(0);
+
+	TInt ret = iLdd.GetDeviceDescriptor(devicePtr);
+
+	if (ret != KErrNone)
+		{
+		LOGTEXT2(_L8("Unable to fetch device descriptor. Error: %d"), ret);
+		LEAVEL(ret);
+		}
+
+	TUsbDeviceDescriptor* deviceDescriptor = reinterpret_cast<TUsbDeviceDescriptor*>(
+		const_cast<TUint8*>(devicePtr.Ptr()));
+
+
+#else
+
+	// Create an empty descriptor to allow the settings
+	// to be read in from the resource file
+	TUsbDeviceDescriptor descriptor;
+	TUsbDeviceDescriptor* deviceDescriptor = &descriptor;
+	
+#endif // __WINS__
+
+	if (iPersonalityCfged)
+		{
+		SetUsbDeviceSettingsFromPersonalityL(*deviceDescriptor);		
+		}
+	else
+		{
+	SetUsbDeviceSettingsL(*deviceDescriptor);
+		}
+	
+#ifndef __WINS__
+	ret = iLdd.SetDeviceDescriptor(devicePtr);
+
+	if (ret != KErrNone)
+		{
+		LOGTEXT2(_L8("Unable to set device descriptor. Error: %d"), ret);
+		LEAVEL(ret);
+		}
+
+	CleanupStack::PopAndDestroy(deviceBuf);
+
+#endif // __WINS__
+	}
+
+void CUsbDevice::SetUsbDeviceSettingsDefaultsL(CUsbDevice::TUsbDeviceDescriptor& aDeviceDescriptor)
+/**
+ * Set the device settings defaults, as per the non-resource
+ * version of the USB manager
+ *
+ * @param aDeviceDescriptor The device descriptor for the USB device
+ */
+	{
+	aDeviceDescriptor.iDeviceClass		= KUsbDefaultDeviceClass;
+	aDeviceDescriptor.iDeviceSubClass	= KUsbDefaultDeviceSubClass;
+	aDeviceDescriptor.iDeviceProtocol	= KUsbDefaultDeviceProtocol;
+	aDeviceDescriptor.iIdVendor			= KUsbDefaultVendorId;
+	aDeviceDescriptor.iIdProduct		= KUsbDefaultProductId;
+	}
+
+void CUsbDevice::SetUsbDeviceSettingsL(CUsbDevice::TUsbDeviceDescriptor& aDeviceDescriptor)
+/**
+ * Configure the USB device, reading in the settings from a
+ * resource file where possible.
+ *
+ * @param aDeviceDescriptor The device descriptor for the USB device
+ */
+	{
+	LOG_FUNC
+
+	// First, use the default values
+	LOGTEXT(_L8("Setting default values for the configuration"));
+	SetUsbDeviceSettingsDefaultsL(aDeviceDescriptor);
+
+	// Now try to get the configuration from the resource file
+	RFs fs;
+	LEAVEIFERRORL(fs.Connect());
+	CleanupClosePushL(fs);
+
+	RResourceFile resource;
+	TRAPD(err, resource.OpenL(fs, KUsbManagerResource));
+	LOGTEXT2(_L8("Opened resource file with error %d"), err);
+
+	if (err != KErrNone)
+		{
+		LOGTEXT(_L8("Unable to open resource file: using default settings"));
+		CleanupStack::PopAndDestroy(&fs);
+		return;
+		}
+
+	CleanupClosePushL(resource);
+
+	resource.ConfirmSignatureL(KUsbManagerResourceVersion);
+
+	HBufC8* id = resource.AllocReadLC(USB_CONFIG);
+
+	// The format of the USB resource structure is:
+	//
+	//	STRUCT usb_configuration
+	//		{
+	//		WORD	vendorId		= 0x0e22;
+	//		WORD	productId		= 0x000b;
+	//		WORD	bcdDevice		= 0x0000;
+	//		LTEXT	manufacturer	= "Symbian Ltd.";
+	//		LTEXT	product			= "Symbian OS";
+	//		}
+	//
+	// Note that the resource must be read in this order!
+	
+	TResourceReader reader;
+	reader.SetBuffer(id);
+
+	aDeviceDescriptor.iIdVendor = static_cast<TUint16>(reader.ReadUint16());
+	aDeviceDescriptor.iIdProduct = static_cast<TUint16>(reader.ReadUint16());
+	aDeviceDescriptor.iBcdDevice = static_cast<TUint16>(reader.ReadUint16());
+
+	// Try to read device and manufacturer name from new SysUtil API
+	TPtrC16 sysUtilModelName;
+	TPtrC16 sysUtilManuName;
+	
+	// This method returns ownership.
+	CDeviceTypeInformation* deviceInfo = SysUtil::GetDeviceTypeInfoL();
+	CleanupStack::PushL(deviceInfo);
+	TInt gotSysUtilModelName = deviceInfo->GetModelName(sysUtilModelName);
+	TInt gotSysUtilManuName = deviceInfo->GetManufacturerName(sysUtilManuName);
+	
+	TPtrC manufacturerString = reader.ReadTPtrC();
+	TPtrC productString = reader.ReadTPtrC();
+	
+	// If we succesfully read the manufacturer or device name from SysUtil API
+	// then set these results, otherwise use the values defined in resource file
+#ifndef __WINS__
+	if (gotSysUtilManuName == KErrNone)
+		{
+		LEAVEIFERRORL(iLdd.SetManufacturerStringDescriptor(sysUtilManuName));
+		}
+	else
+		{
+		LEAVEIFERRORL(iLdd.SetManufacturerStringDescriptor(manufacturerString));
+		}
+
+	if (gotSysUtilModelName == KErrNone)
+		{
+		LEAVEIFERRORL(iLdd.SetProductStringDescriptor(sysUtilModelName));
+		}
+	else
+		{
+		LEAVEIFERRORL(iLdd.SetProductStringDescriptor(productString));
+		}
+#endif // __WINS__
+
+#ifdef __FLOG_ACTIVE
+	PrintDescriptor(aDeviceDescriptor);	
+	TBuf8<KUsbStringDescStringMaxSize> narrowString;
+	narrowString.Copy(manufacturerString);
+	LOGTEXT2(_L8("Manufacturer is: '%S'"), &narrowString);
+	narrowString.Copy(productString);
+	LOGTEXT2(_L8("Product is: '%S'"), &narrowString);
+#endif // __FLOG_ACTIVE
+
+#ifndef __WINS__	
+	//Read the published serial number. The key is the UID KUidUsbmanServer = 0x101FE1DB
+	TBuf16<KUsbStringDescStringMaxSize> serNum;
+	TInt r = RProperty::Get(KUidSystemCategory,0x101FE1DB,serNum);
+	if(r==KErrNone)
+		{
+#ifdef __FLOG_ACTIVE
+		TBuf8<KUsbStringDescStringMaxSize> narrowString;
+		narrowString.Copy(serNum);
+		LOGTEXT2(_L8("Setting published SerialNumber: %S"), &narrowString);
+#endif // __FLOG_ACTIVE
+		//USB spec doesn't give any constraints on what constitutes a valid serial number.
+		//As long as it is a string descriptor it is valid.
+		LEAVEIFERRORL(iLdd.SetSerialNumberStringDescriptor(serNum));	
+		}
+#ifdef __FLOG_ACTIVE
+	else
+		{
+		LOGTEXT(_L8("SerialNumber has not been published"));	
+		}
+#endif // __FLOG_ACTIVE
+#endif // __WINS__
+
+
+	CleanupStack::PopAndDestroy(4, &fs); //  deviceInfo, id, resource, fs
+	}
+
+void CUsbDevice::SetUsbDeviceSettingsFromPersonalityL(CUsbDevice::TUsbDeviceDescriptor& aDeviceDescriptor)
+/**
+ * Configure the USB device from the current personality.
+ *
+ * @param aDeviceDescriptor The device descriptor for the USB device
+ */
+	{
+	LOG_FUNC
+
+	// First, use the default values
+	LOGTEXT(_L8("Setting default values for the configuration"));
+	SetUsbDeviceSettingsDefaultsL(aDeviceDescriptor);
+
+	// Now try to get the configuration from the current personality
+	const CUsbDevice::TUsbDeviceDescriptor& deviceDes = iCurrentPersonality->DeviceDescriptor();
+	aDeviceDescriptor.iDeviceClass			= deviceDes.iDeviceClass;
+	aDeviceDescriptor.iDeviceSubClass		= deviceDes.iDeviceSubClass;
+	aDeviceDescriptor.iDeviceProtocol		= deviceDes.iDeviceProtocol;
+	aDeviceDescriptor.iIdVendor				= deviceDes.iIdVendor;
+	aDeviceDescriptor.iIdProduct			= deviceDes.iIdProduct;
+	aDeviceDescriptor.iBcdDevice			= deviceDes.iBcdDevice;
+	aDeviceDescriptor.iSerialNumber			= deviceDes.iSerialNumber;
+	aDeviceDescriptor.iNumConfigurations	= deviceDes.iNumConfigurations;
+
+#ifndef __WINS__
+	LEAVEIFERRORL(iLdd.SetManufacturerStringDescriptor(*(iCurrentPersonality->Manufacturer())));
+	LEAVEIFERRORL(iLdd.SetProductStringDescriptor(*(iCurrentPersonality->Product())));
+
+	//Read the published serial number. The key is the UID KUidUsbmanServer = 0x101FE1DB
+	TBuf16<KUsbStringDescStringMaxSize> serNum;
+	TInt r = RProperty::Get(KUidSystemCategory,0x101FE1DB,serNum);
+	if(r==KErrNone)
+		{
+#ifdef __FLOG_ACTIVE
+		TBuf8<KUsbStringDescStringMaxSize> narrowString;
+		narrowString.Copy(serNum);
+		LOGTEXT2(_L8("Setting published SerialNumber: %S"), &narrowString);
+#endif // __FLOG_ACTIVE
+		//USB spec doesn't give any constraints on what constitutes a valid serial number.
+		//As long as it is a string descriptor it is valid.
+		LEAVEIFERRORL(iLdd.SetSerialNumberStringDescriptor(serNum));	
+		}
+#ifdef __FLOG_ACTIVE
+	else
+		{
+		LOGTEXT(_L8("SerialNumber has not been published"));	
+		}
+#endif // __FLOG_ACTIVE
+#endif // __WINS__
+
+
+#ifdef __FLOG_ACTIVE
+	PrintDescriptor(aDeviceDescriptor);		
+
+#ifndef __WINS__
+	TBuf16<KUsbStringDescStringMaxSize> wideString;
+	TBuf8<KUsbStringDescStringMaxSize> narrowString;
+
+	LEAVEIFERRORL(iLdd.GetConfigurationStringDescriptor(wideString));
+	narrowString.Copy(wideString);
+	LOGTEXT2(_L8("Configuration is: '%S'"), &narrowString);
+#endif // __WINS__
+
+#endif // __FLOG_ACTIVE
+	}
+	
+void CUsbDevice::TryStartL(TInt aPersonalityId)
+/**
+ * Start all USB classes associated with the personality identified
+ * by aPersonalityId. Reports errors and state changes via observer 
+ * interface.
+ *
+ * @param aPersonalityId a personality id
+ */
+	{
+	LOG_FUNC
+	SetCurrentPersonalityL(aPersonalityId);
+	
+	SelectClassControllersL();
+	SetServiceState(EUsbServiceStarting);
+
+	TRAPD(err, SetDeviceDescriptorL());
+	if ( err != KErrNone )
+		{
+		SetServiceState(EUsbServiceIdle);
+		LEAVEL(err);		
+		}
+
+	iLastError = KErrNone;
+	StartCurrentClassController();
+ 	}
+ 	
+TInt CUsbDevice::CurrentPersonalityId() const
+/**
+ * @return the current personality id
+ */
+ 	{
+	LOG_FUNC
+ 	return iCurrentPersonality->PersonalityId();
+ 	}
+ 	
+const RPointerArray<CPersonality>& CUsbDevice::Personalities() const
+/**
+ * @return a const reference to RPointerArray<CPersonality>
+ */
+ 	{
+	LOG_FUNC
+ 	return iSupportedPersonalities;
+ 	} 
+ 	
+const CPersonality* CUsbDevice::GetPersonality(TInt aPersonalityId) const
+/**
+ * Obtains a handle to the CPersonality object whose id is aPersonalityId
+ *
+ * @param aPeraonalityId a personality id
+ * @return a const pointer to the CPersonality object whose id is aPersonalityId if found
+ * or 0 otherwise.
+ */
+	{
+	LOG_FUNC
+	
+	TInt count = iSupportedPersonalities.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+		if (iSupportedPersonalities[i]->PersonalityId() == aPersonalityId)
+			{
+			return iSupportedPersonalities[i];
+			}
+		}
+	
+	return 0;
+	}
+	
+void CUsbDevice::SetCurrentPersonalityL(TInt aPersonalityId)
+/**
+ * Sets the current personality to the personality with id aPersonalityId
+ */
+ 	{
+	LOG_FUNC
+	const CPersonality* personality = GetPersonality(aPersonalityId);
+	if (!personality)
+		{
+		LOGTEXT(_L8("Personality id not found"));
+		LEAVEL(KErrNotFound);
+		}
+		
+	iCurrentPersonality = personality;
+ 	}
+	
+void CUsbDevice::ValidatePersonalitiesL()
+/**
+ * Verifies all class controllers associated with each personality are loaded.
+ * Leave if validation fails.
+ */
+	{
+	LOG_FUNC
+
+	TInt personalityCount = iSupportedPersonalities.Count();
+	for (TInt i = 0; i < personalityCount; i++)
+		{
+		const RArray<TUid>& classUids = iSupportedPersonalities[i]->SupportedClasses();
+		TInt uidCount = classUids.Count();
+		for (TInt j = 0; j < uidCount; j++)	
+			{
+			TInt ccCount = iSupportedClassUids.Count();
+			TInt k;
+			for (k = 0; k < ccCount; k++)
+				{
+				if (iSupportedClassUids[k] == classUids[j])
+					{
+					break;
+					}
+				}
+			if (k == ccCount)
+				{
+				LOGTEXT(_L8("personality validation failed"));
+				LEAVEL(KErrAbort);
+				}					
+			}	
+		}
+	}
+/**
+Converts text string with UIDs to array of Uint
+
+If there is an error during the conversion, this function will not clean-up,
+so there may still be UIDs allocated in the RArray.
+
+@param aStr Reference to a string containing one or more UIDs in hex
+@param aUIDs On return array of UIDs parsed from the input string
+@panic EUidArrayNotEmpty if the RArray passed in is not empty
+*/
+void CUsbDevice::ConvertUidsL(const TDesC& aStr, RArray<TUint>& aUidArray)	
+	{
+	// Function assumes that aUIDs is empty
+	__ASSERT_DEBUG( aUidArray.Count() == 0, _USB_PANIC(KUsbDevicePanicCategory, EUidArrayNotEmpty) );
+
+	TLex input(aStr);
+
+	// Scan through string to find UIDs
+	// Need to do this at least once, as no UID in the string is an error
+	do 
+		{
+		// Find first hex digit
+		while (!(input.Eos() || input.Peek().IsHexDigit()))
+			{
+			input.Inc();	
+			}
+
+		// Convert and add to array
+		TUint val;
+		LEAVEIFERRORL(input.Val(val,EHex));
+		aUidArray.AppendL(val);
+		}
+	while (!input.Eos());	
+	}
+
+void CUsbDevice::ReadPersonalitiesL()
+/**
+ * Reads configured personalities from the resource file
+ */
+	{
+	LOG_FUNC
+	iPersonalityCfged = EFalse;
+	// Now try to connect to file server
+	RFs fs;
+	LEAVEIFERRORL(fs.Connect());
+	CleanupClosePushL(fs);
+
+	TFileName resourceFileName;
+	ResourceFileNameL(resourceFileName);
+	RResourceFile resource;
+	TRAPD(err, resource.OpenL(fs, resourceFileName));
+	LOGTEXT2(_L8("Opened resource file with error %d"), err);
+
+	if (err != KErrNone)
+		{
+		LOGTEXT(_L8("Unable to open resource file"));
+		CleanupStack::PopAndDestroy(&fs);
+		return;
+		}
+
+	CleanupClosePushL(resource);
+
+	TInt resourceVersion = resource.SignatureL();
+	LOGTEXT2(_L8("Resource file signature is %d"), resourceVersion);
+	// Check for the version is valid(EUsbManagerResourceVersionOne, EUsbManagerResourceVersionTwo
+	// or EUsbManagerResourceVersionThree).
+	if(resourceVersion > EUsbManagerResourceVersionThree)
+		{
+		LOGTEXT2(_L8("Version of resource file is valid (>%d)"), EUsbManagerResourceVersionThree);
+		User::LeaveIfError(KErrNotSupported);
+		}
+	
+	resource.ConfirmSignatureL(resourceVersion);
+
+	HBufC8* personalityBuf = 0;
+	TRAPD(ret, personalityBuf = resource.AllocReadL(DEVICE_PERSONALITIES));
+	// If personalities resource is not found, swallow the error and return
+	// as no specified personalities is a valid configuration
+	if (ret == KErrNotFound)
+		{
+		LOGTEXT(_L8("Personalities are not configured"));
+		CleanupStack::PopAndDestroy(2, &fs); 
+		return;
+		}
+	// Otherwise leave noisily if the AllocRead fails
+	LEAVEIFERRORL(ret);
+	CleanupStack::PushL(personalityBuf);
+
+	// The format of the USB resource structure is:
+	//
+	// 	STRUCT PERSONALITY
+	//		{
+	// 		WORD	bcdDeviceClass;
+	// 		WORD	bcdDeviceSubClass;
+	//		WORD 	protocol;
+	//		WORD	numConfigurations;
+	//		WORD 	vendorId;
+	//		WORD 	productId;
+	//		WORD 	bcdDevice;
+	//		LTEXT 	manufacturer;
+	//		LTEXT 	product;
+	//		WORD 	id;					// personality id
+	//		LTEXT	class_uids;	
+	//		LTEXT 	description;		// personality description
+	//     	LTEXT   detailedDescription;  //detailed description. This is in version 2
+	//		LONG 	Property;
+	//		}
+	//
+	// Note that the resource must be read in this order!
+	
+	TResourceReader reader;
+	reader.SetBuffer(personalityBuf);
+
+	TUint16 personalityCount 	= static_cast<TUint16>(reader.ReadUint16());
+	
+	// Read the manufacturer and device name (product) here from SysUtil class
+	TPtrC16 sysUtilModelName;
+	TPtrC16 sysUtilManuName;
+
+	// This method returns ownership.
+	CDeviceTypeInformation* deviceInfo = SysUtil::GetDeviceTypeInfoL();
+	CleanupStack::PushL(deviceInfo);
+	TInt gotSysUtilModelName = deviceInfo->GetModelName(sysUtilModelName);
+	TInt gotSysUtilManuName = deviceInfo->GetManufacturerName(sysUtilManuName);
+	
+	for (TInt idx = 0; idx < personalityCount; idx++)
+		{
+		// read a personality 
+		TUint8 	bDeviceClass 		= static_cast<TUint8>(reader.ReadUint8());
+		TUint8 	bDeviceSubClass 	= static_cast<TUint8>(reader.ReadUint8());
+		TUint8 	protocol 			= static_cast<TUint8>(reader.ReadUint8());
+		TUint8 	numConfigurations	= static_cast<TUint8>(reader.ReadUint8());
+		TUint16 vendorId			= static_cast<TUint16>(reader.ReadUint16());
+		TUint16 productId			= static_cast<TUint16>(reader.ReadUint16());
+		TUint16 bcdDevice			= static_cast<TUint16>(reader.ReadUint16());
+		TPtrC	manufacturer		= reader.ReadTPtrC();
+		TPtrC	product				= reader.ReadTPtrC();
+		TUint16 id					= static_cast<TUint16>(reader.ReadUint16());
+		TPtrC	uidsStr				= reader.ReadTPtrC();
+		TPtrC 	description			= reader.ReadTPtrC();
+		
+		RArray<TUint> uids;
+		CleanupClosePushL(uids);
+		ConvertUidsL(uidsStr, uids);
+		// creates a CPersonality object
+		CPersonality* personality = CPersonality::NewL();
+		CleanupStack::PushL(personality);
+
+		personality->SetVersion(resourceVersion);
+		
+		// populates personality object
+		personality->SetId(id);
+		        
+		for (TInt uidIdx = 0; uidIdx < uids.Count(); uidIdx++)
+			{
+			LEAVEIFERRORL(personality->AddSupportedClasses(TUid::Uid(uids[uidIdx])));
+			}
+		
+		// gets a handle to iDeviceDescriptor of personality
+		CUsbDevice::TUsbDeviceDescriptor& dvceDes = personality->DeviceDescriptor();
+		if (gotSysUtilManuName == KErrNone)
+			{
+			personality->SetManufacturer(&sysUtilManuName);
+			}
+		else
+			{
+			personality->SetManufacturer(&manufacturer);
+			}
+			
+		if (gotSysUtilModelName == KErrNone)
+			{
+			personality->SetProduct(&sysUtilModelName);
+			}
+		else
+			{
+			personality->SetProduct(&product);
+			}
+			
+		personality->SetDescription(&description);
+		dvceDes.iDeviceClass = bDeviceClass;
+		dvceDes.iDeviceSubClass = bDeviceSubClass;
+		dvceDes.iDeviceProtocol = protocol;
+		dvceDes.iIdVendor = vendorId;
+		dvceDes.iIdProduct= productId;
+		dvceDes.iBcdDevice = bcdDevice;
+		dvceDes.iNumConfigurations = numConfigurations;
+		
+		//detailedDescription is only supported after EUsbManagerResourceVersionTwo
+		if(resourceVersion >= EUsbManagerResourceVersionTwo)
+			{
+			TPtrC   detailedDescription = reader.ReadTPtrC();        
+			personality->SetDetailedDescription(&detailedDescription);
+#ifdef __FLOG_ACTIVE
+			TBuf8<KUsbDescMaxSize_String> narrowLongBuf;
+			narrowLongBuf.Copy(detailedDescription);
+			LOGTEXT2(_L8("detailed description = '%S'"),        &narrowLongBuf);            
+#endif // __FLOG_ACTIVE
+			}
+
+		//Property is only supported after EUsbManagerResourceVersionThree
+		if(resourceVersion >= EUsbManagerResourceVersionThree)
+			{
+			TUint32 property			= static_cast<TUint32>(reader.ReadUint32());
+			personality->SetProperty(property);
+#ifdef __FLOG_ACTIVE
+		LOGTEXT2(_L8("property = %d\n"), 			property);
+#endif // __FLOG_ACTIVE
+			}
+		
+		// Append personality to iSupportedPersonalities
+		iSupportedPersonalities.AppendL(personality);
+		// Now pop off personality
+		CleanupStack::Pop(personality);
+#ifdef __FLOG_ACTIVE
+		// Debugging
+		LOGTEXT2(_L8("personalityCount = %d\n"), 	personalityCount);
+		LOGTEXT2(_L8("bDeviceClass = %d\n"), 		bDeviceClass);
+		LOGTEXT2(_L8("bDeviceSubClass = %d\n"), 	bDeviceSubClass);
+		LOGTEXT2(_L8("protocol = %d\n"), 			protocol);
+		LOGTEXT2(_L8("numConfigurations = %d\n"), 	numConfigurations);
+		LOGTEXT2(_L8("vendorId = %d\n"), 			vendorId);
+		LOGTEXT2(_L8("productId = %d\n"), 			productId);
+		LOGTEXT2(_L8("bcdDevice = %d\n"), 			bcdDevice);
+		TBuf8<KMaxName> narrowBuf;
+		narrowBuf.Copy(manufacturer);
+		LOGTEXT2(_L8("manufacturer = '%S'"), 		&narrowBuf);
+		narrowBuf.Copy(product);
+		LOGTEXT2(_L8("product = '%S'"), 			&narrowBuf);
+		LOGTEXT2(_L8("id = %d\n"), 					id);
+		LOGTEXT(_L8("ClassUids{"));
+		for (TInt k = 0; k < uids.Count(); k++)
+			{
+			LOGTEXT2(_L8("%d"), uids[k]);
+			}
+		LOGTEXT(_L8("}"));
+		narrowBuf.Copy(description);
+		LOGTEXT2(_L8("description = '%S'"), 		&narrowBuf);
+#endif // __FLOG_ACTIVE
+		CleanupStack::PopAndDestroy(&uids);	// close uid array		
+		}
+		
+	CleanupStack::PopAndDestroy(4, &fs); // deviceInfo, personalityBuf, resource, fs
+	iPersonalityCfged = ETrue;	
+	}
+	
+void CUsbDevice::SelectClassControllersL()
+/**
+ * Selects class controllers for the current personality
+ */
+	{
+	LOG_FUNC
+
+	CreateClassControllersL(iCurrentPersonality->SupportedClasses());
+	}
+#ifdef USE_DUMMY_CLASS_CONTROLLER	
+void CUsbDevice::CreateClassControllersL(const RArray<TUid>& /* aClassUids*/)
+#else 
+void CUsbDevice::CreateClassControllersL(const RArray<TUid>& aClassUids)
+#endif
+/**
+ * Creates a class controller object for each class uid
+ *
+ * @param aClassUids an array of class uids
+ */
+ 	{
+	LOG_FUNC
+
+#ifndef USE_DUMMY_CLASS_CONTROLLER
+
+	//create a TLinearOrder to supply the comparison function, Compare(), to be used  
+	//to determine the order to add class controllers
+	TLinearOrder<CUsbClassControllerBase> order(CUsbClassControllerBase::Compare);
+
+	TInt count = aClassUids.Count();
+	
+	// destroy any class controller objects in iSupportedClasses and reset it for reuse
+	iSupportedClasses.ResetAndDestroy();
+	LOGTEXT2(_L8("aClassUids.Count() = %d\n"), 	count);
+	for (TInt i = 0; i < count; i++)
+		{ 
+		CUsbClassControllerPlugIn* plugIn = CUsbClassControllerPlugIn::NewL(aClassUids[i], *this);
+		AddClassControllerL(reinterpret_cast<CUsbClassControllerBase*>(plugIn), order);
+		} 
+#endif // USE_DUMMY_CLASS_CONTROLLER	
+
+	LEAVEIFERRORL(iUsbClassControllerIterator->First());
+ 	}
+
+void CUsbDevice::SetDefaultPersonalityL()
+/**
+ * Sets default personality. Used for Start request.
+ */
+	{
+	LOG_FUNC
+
+	TInt smallestId = iSupportedPersonalities[0]->PersonalityId();
+ 	TInt count = iSupportedPersonalities.Count();
+ 	
+ 	for (TInt i = 1; i < count; i++)
+ 		{
+ 		if(iSupportedPersonalities[i]->PersonalityId() < smallestId)
+ 			{
+ 			smallestId = iSupportedPersonalities[i]->PersonalityId();
+ 			}
+ 		}
+
+	SetCurrentPersonalityL(smallestId);
+	SelectClassControllersL();
+	}
+
+void CUsbDevice::LoadFallbackClassControllersL()
+/**
+ * Load class controllers for fallback situation:
+ * no personalities are configured.
+ * This method inserts all class controllers to 
+ * the list from which they will be either all started
+ * or stopped
+ */
+ 	{
+	LOG_FUNC
+ 	SetDeviceDescriptorL();
+	CreateClassControllersL(iSupportedClassUids);
+ 	}
+ 	
+void CUsbDevice::ResourceFileNameL(TFileName& aFileName)
+/**
+ * Gets resource file name
+ *
+ * @param aFileName Descriptor to populate with resource file name
+ */
+ 	{
+	LOG_FUNC
+
+	RFs fs;
+	LEAVEIFERRORL(fs.Connect());
+	CleanupClosePushL(fs);
+
+#ifdef __WINS__
+	// If we are running in the emulator then read the resource file from system drive.
+	// This makes testing with different resource files easier.
+	_LIT(KPrivatePath, ":\\Private\\101fe1db\\");
+	aFileName.Append(RFs::GetSystemDriveChar()); //get the name of system drive
+	aFileName.Append(KPrivatePath);
+#else
+ 	const TDriveNumber KResourceDrive = EDriveZ;
+
+	TDriveUnit driveUnit(KResourceDrive);
+	TDriveName drive=driveUnit.Name();
+	aFileName.Insert(0, drive);
+	// append private path
+	TPath privatePath;
+	fs.PrivatePath(privatePath);
+	aFileName.Append(privatePath);		
+#endif //WINS
+
+	// Find the nearest match of resource file for the chosen locale
+	aFileName.Append(_L("usbman.rsc"));
+	BaflUtils::NearestLanguageFile(fs, aFileName); // if a match is not found, usbman.rsc will be used
+
+	CleanupStack::PopAndDestroy(&fs);	// fs no longer needed
+ 	}
+
+RDevUsbcClient& CUsbDevice::MuepoDoDevUsbcClient()
+/**
+ * Inherited from MUsbmanExtensionPluginObserver - Function used by plugins to
+ * retrieve our handle to the LDD
+ *
+ * @return The LDD handle
+ */
+	{
+	return iLdd;
+	}
+
+void CUsbDevice::MuepoDoRegisterStateObserverL(MUsbDeviceNotify& aObserver)
+/**
+ * Inherited from MUsbmanExtensionPluginObserver - Function used by plugins to
+ * register themselves for notifications of device/service state changes.
+ *
+ * @param aObserver New Observer of the device
+ */
+	{
+	LOGTEXT2(_L8("CUsbDevice::MuepoDoRegisterStateObserverL aObserver = 0x%08x"),&aObserver);
+	RegisterObserverL(aObserver);
+	}