--- /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);
+ }