diff -r 000000000000 -r c9bc50fca66e usbmgmt/usbmgr/host/fdf/production/server/src/fdf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbmgmt/usbmgr/host/fdf/production/server/src/fdf.cpp Tue Feb 02 02:02:59 2010 +0200 @@ -0,0 +1,1450 @@ +/* +* Copyright (c) 2007-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: +* +*/ + +/** + @file + @internalComponent +*/ + +#include "fdf.h" +#include +#include "utils.h" +#include +#include "eventqueue.h" + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, "fdf "); +#endif + +_LIT(KDriverUsbhubLddFileName,"usbhubdriver"); +_LIT(KDriverUsbdiLddFileName,"usbdi"); + +PANICCATEGORY("fdf"); + +const TUint KVendorSpecificDeviceClassValue = 0xFF; +const TUint KVendorSpecificInterfaceClassValue = 0xFF; +const TUint KMaxSearchKeyLength = 64; + +// Factory function for TInterfaceInfo objects. +CFdf::TInterfaceInfo* CFdf::TInterfaceInfo::NewL(RPointerArray& aInterfaces) + { + LOG_STATIC_FUNC_ENTRY + + TInterfaceInfo* self = new(ELeave) TInterfaceInfo; + CleanupStack::PushL(self); + aInterfaces.AppendL(self); + CLEANUPSTACK_POP1(self); + return self; + } + + +CFdf* CFdf::NewL() + { + LOG_STATIC_FUNC_ENTRY + + CFdf* self = new(ELeave) CFdf; + CleanupStack::PushL(self); + self->ConstructL(); + CLEANUPSTACK_POP1(self); + return self; + } + +CFdf::CFdf() +: iDevices(_FOFF(CDeviceProxy, iLink)), + iFunctionDrivers(_FOFF(CFdcProxy, iLink)) + { + LOG_FUNC + } + +void CFdf::ConstructL() + { + LOG_FUNC + +#ifndef __OVER_DUMMYUSBDI__ + // If we're using the DummyUSBDI we don't need the real USBDI. + TInt err = User::LoadLogicalDevice(KDriverUsbhubLddFileName); + if ( err != KErrAlreadyExists ) + { + LEAVEIFERRORL(err); + } +#endif // __OVER_DUMMYUSBDI__ + + LEAVEIFERRORL(iHubDriver.Open()); + +#ifdef __OVER_DUMMYUSBDI__ + LEAVEIFERRORL(iHubDriver.StartHost()); +#endif + + iActiveWaitForBusEvent = CActiveWaitForBusEvent::NewL(iHubDriver, iBusEvent, *this); + iActiveWaitForBusEvent->Wait(); + + CreateFunctionDriverProxiesL(); + + iActiveWaitForEComEvent = CActiveWaitForEComEvent::NewL(*this); + iActiveWaitForEComEvent->Wait(); + + iEventQueue = CEventQueue::NewL(*this); + } + +void CFdf::CreateFunctionDriverProxiesL() + { + + LOG_FUNC + REComSession::ListImplementationsL(TUid::Uid(KFdcEcomInterfaceUid), iImplInfoArray); + const TUint count = iImplInfoArray.Count(); + LOGTEXT2(_L8("\tiImplInfoArray.Count() upon FDF creation = %d"), count); +#ifdef __FLOG_ACTIVE + if ( count == 0 ) + { + LOGTEXT(_L8("\tTHERE ARE NO FUNCTION DRIVERS PRESENT IN THE SYSTEM")); + } + else + { + for (TInt kk = 0; kk < count; ++kk) + LOGTEXT3(_L8("\t\tFDC implementation Index:%d UID: 0x%08x"), kk, iImplInfoArray[kk]->ImplementationUid()); + } +#endif + + for ( TUint i = 0 ; i < count ; ++i ) + { + CFdcProxy* proxy = CFdcProxy::NewL(*this, *iImplInfoArray[i]); + + // If this proxy is rom based then put it in the first place + // this will save time when trying to load the FDC with the rule of + // ROM-based ones have higher priority than installed ones. + if (proxy->RomBased()) + iFunctionDrivers.AddFirst(*proxy); + else + iFunctionDrivers.AddLast(*proxy); + } + } + +CFdf::~CFdf() + { + LOG_FUNC + + // Mimic the detachment of each attached device. + TSglQueIter deviceIter(iDevices); + deviceIter.SetToFirst(); + CDeviceProxy* device; + while ( ( device = deviceIter++ ) != NULL ) + { + const TUint deviceId = device->DeviceId(); + LOGTEXT2(_L8("\tmimicking detachment of device with id %d"), device); + TellFdcsOfDeviceDetachment(deviceId); + iDevices.Remove(*device); + delete device; + } + + // Destroy all the FDC proxies. They should each now have no 'attached + // devices' and no plugin instance. + TSglQueIter fdcIter(iFunctionDrivers); + fdcIter.SetToFirst(); + CFdcProxy* fdc; + while ( ( fdc = fdcIter++ ) != NULL ) + { + iFunctionDrivers.Remove(*fdc); + delete fdc; + } + + delete iActiveWaitForBusEvent; + + delete iActiveWaitForEComEvent; + + if ( iHubDriver.Handle() ) + { + iHubDriver.StopHost(); // NB this has no return value + } + iHubDriver.Close(); + +#ifndef __OVER_DUMMYUSBDI__ + //If we're using the DummyUSBDI the real USBDI isn't loaded. + TInt err = User::FreeLogicalDevice(KDriverUsbhubLddFileName); + LOGTEXT2(_L8("\tFreeLogicalDevice( usbhubdriver ) returned %d"), err); + + err = User::FreeLogicalDevice(KDriverUsbdiLddFileName); + LOGTEXT2(_L8("\tFreeLogicalDevice( usbdi ) returned %d"), err); +#endif // __OVER_DUMMYUSBDI__ + + delete iEventQueue; + + // This is a worthwhile check to do at this point. If we ever don't clean + // up iInterfaces at the *right* time, then this will be easier to debug + // than a memory leak. + ASSERT_DEBUG(iInterfaces.Count() == 0); + + iImplInfoArray.ResetAndDestroy(); + REComSession::FinalClose(); + } + +void CFdf::EnableDriverLoading() + { + LOG_FUNC + + iDriverLoadingEnabled = ETrue; + } + +void CFdf::DisableDriverLoading() + { + LOG_FUNC + + iDriverLoadingEnabled = EFalse; + } + +void CFdf::SetSession(CFdfSession* aSession) + { + LOG_FUNC + LOGTEXT2(_L8("\taSession = 0x%08x"), aSession); + + iSession = aSession; + } + +CFdfSession* CFdf::Session() + { + return iSession; + } + +TBool CFdf::GetDeviceEvent(TDeviceEvent& aEvent) + { + LOG_FUNC + + ASSERT_DEBUG(iEventQueue); + return iEventQueue->GetDeviceEvent(aEvent); + } + +TBool CFdf::GetDevmonEvent(TInt& aEvent) + { + LOG_FUNC + + ASSERT_DEBUG(iEventQueue); + return iEventQueue->GetDevmonEvent(aEvent); + } + + +// An ECom plugin has been installed or removed +void CFdf::EComEventReceived() + { + TRAPD(ret, HandleEComEventReceivedL()); + if (ret != KErrNone) + HandleDevmonEvent(KErrUsbUnableToUpdateFDProxyList); + + } + +void CFdf::HandleEComEventReceivedL() + { + LOG_FUNC + + // There is no way to filter ecom notification to only receive ones we are interested in, also there is no way + // to query ecom as to what has changed. Hence there is no option but to call ListImplementations(). + iImplInfoArray.ResetAndDestroy(); + + REComSession::ListImplementationsL(TUid::Uid(KFdcEcomInterfaceUid), iImplInfoArray); + TUint implementationsCount = iImplInfoArray.Count(); + LOGTEXT2(_L8("\tiImplInfoArray.Count() after ECom notification= %d"), implementationsCount); + +#ifdef __FLOG_ACTIVE + if ( implementationsCount == 0 ) + { + LOGTEXT(_L8("\tTHERE ARE NO FUNCTION DRIVERS PRESENT IN THE SYSTEM")); + } + + TSglQueIter proxiesIterDebug(iFunctionDrivers); + CFdcProxy* fdcDebug = NULL; + while ( ( fdcDebug = proxiesIterDebug++ ) != NULL ) + { + TUid fdcUid = fdcDebug->ImplUid(); + LOGTEXT2(_L8("\t\tOld FDC Proxy implementation UID: 0x%08x"), fdcUid.iUid); + TInt fdcVersion = fdcDebug->Version(); + LOGTEXT2(_L8("\t\tFDC Proxy version UID: %d"), fdcVersion); + } + LOGTEXT(_L8("\t\t------------------------------------------------------------------")); + for (TInt kk = 0; kk < implementationsCount; ++kk) + { + TUid fdcUid2 = iImplInfoArray[kk]->ImplementationUid(); + LOGTEXT2(_L8("\t\tNew FDC Proxy implementation UID: 0x%08x"), fdcUid2.iUid); + TInt fdcVersion2 = iImplInfoArray[kk]->Version(); + LOGTEXT2(_L8("\t\tFDC Proxy version UID: %d"), fdcVersion2); + } +#endif + + // See if any relevant FDCs (or upgrades) have been installed or uninstalled: + + // For each FD in the proxy list compare the uid and version with each FD returned by ECom looking + // for the removal, upgrade or downgrade of an existing FD + TSglQueIter proxiesIter(iFunctionDrivers); + proxiesIter.SetToFirst(); + CFdcProxy* fdc = NULL; + while ( ( fdc = proxiesIter++ ) != NULL ) + { + TBool fdcRemoved = ETrue; + for (TInt ii = 0; ii < implementationsCount; ++ii) + { + if (fdc->ImplUid() == iImplInfoArray[ii]->ImplementationUid()) + { + // We have found an upgrade, downgrade, or duplicate (a duplicate could occur in the situation + // where an FD has been installed, then a device attached, then the FD uninstalled and re-installed *while* + // the device is still attached (meaning the FD's proxy is still in the proxy list but will have been marked + // for deletion when the uninstallation was detected). + fdcRemoved = EFalse; + if (fdc->Version() != iImplInfoArray[ii]->Version()) + { + // We've found an upgrade or a downgrade. Note that the upgrade FD proxy needs adding to the + // proxy list, however that isn't done here it is done later in the loop that is searching for + // new FDs. This is to prevent its possible duplicate addition [consider the situation where + // there is FDv1 and a device is attached, then while still attached FDv2 gets installed (while will + // result in FDv1 getting marked for deletion), then another device is attached which will use FDv2. + // Now if FDv3 is installed before any of the devices were detached there will be two proxies in the + // proxy list with the same UID but differing version numbers. If FDv3 is added here it will therefore + // be added twice]. + if (fdc->DeviceCount()) + { + // The device using the FD is still attached + fdc->MarkForDeletion(); + } + else + { + iFunctionDrivers.Remove(*fdc); + delete fdc; + } + } + else + { + // we've found an FD being installed which is still currently + // active in the proxy list + fdc->UnmarkForDeletion(); + } + // Since we found the plugin with the same implementationUid + // we could simply bail out to stop the looping; + break; + } + } + if (fdcRemoved) + { + // An FDC has been uninstalled - if the FDC isn't in use remove it + // otherwise mark it for deletion + if (fdc->DeviceCount()) + fdc->MarkForDeletion(); + else + { + iFunctionDrivers.Remove(*fdc); + delete fdc; + } + } + } + + + // For each FD returned by ECom, search and compare with the FD proxy list + // looking for new FDs + for (TInt ii = 0; ii < implementationsCount; ++ii) + { + TBool newFdcFound = ETrue; + proxiesIter.SetToFirst(); + while ( ( fdc = proxiesIter++ ) != NULL ) + { + if (fdc->ImplUid() == iImplInfoArray[ii]->ImplementationUid() && fdc->Version() == iImplInfoArray[ii]->Version()) + { + // No need to create a new proxy if there is one with a matching UID and version. + newFdcFound = EFalse; + + // We break out this loop for efficiency. + break; + } + } + + if (newFdcFound) + { + // A new or upgrade FDC has been installed onto the device + CFdcProxy* proxy = CFdcProxy::NewL(*this, *iImplInfoArray[ii]); + + // If this proxy is rom based then put it in the first place + // this will save time when trying to load the FDC with the rule that + // ROM-based ones have higher priority than installed ones. + if (proxy->RomBased()) + iFunctionDrivers.AddFirst(*proxy); + else + iFunctionDrivers.AddLast(*proxy); + } + } + } + +// A bus event has occurred. +void CFdf::MbeoBusEvent() + { + LOG_FUNC + LOGTEXT2(_L8("\tiBusEvent.iEventType = %d"), iBusEvent.iEventType); + LOGTEXT2(_L8("\tiBusEvent.iError = %d"), iBusEvent.iError); + LOGTEXT2(_L8("\tiBusEvent.iDeviceHandle = %d"), iBusEvent.iDeviceHandle); + + switch ( iBusEvent.iEventType ) + { + case RUsbHubDriver::TBusEvent::EDeviceAttached: + if ( !iBusEvent.iError ) + { + // So far, a successful attachment. + HandleDeviceAttachment(iBusEvent.iDeviceHandle); + } + else + { + // It was an attachment failure. Simply tell the event queue. + ASSERT_DEBUG(iEventQueue); + iEventQueue->AttachmentFailure(iBusEvent.iError); + } + break; + + case RUsbHubDriver::TBusEvent::EDeviceRemoved: + // Device detachments are always 'KErrNone'. If the device was + // pseudo-detached due to an overcurrent condition (for instance) then + // the overcurrent condition is indicated through the devmon API (i.e. + // EDevMonEvent) and the detachment is still 'KErrNone'. + ASSERT_DEBUG(iBusEvent.iError == KErrNone); + HandleDeviceDetachment(iBusEvent.iDeviceHandle); + break; + + case RUsbHubDriver::TBusEvent::EDevMonEvent: + HandleDevmonEvent(iBusEvent.iError); + break; + + case RUsbHubDriver::TBusEvent::ENoEvent: + default: + break; + } + + // Only re-post the notification when we've finished examining the + // TBusEvent from the previous completion. (Otherwise it might get + // overwritten.) + iActiveWaitForBusEvent->Wait(); + } + +// This is the central handler for device attachment. +// We deal with device attachments in two phases. +// The first phase is confusingly called device attachment. +// The second phase is driver loading. +void CFdf::HandleDeviceAttachment(TUint aDeviceId) + { + LOG_FUNC + // This is filled in by HandleDeviceAttachmentL on success. + CDeviceProxy* device; + TRAPD(err, HandleDeviceAttachmentL(aDeviceId, device)); + if ( err ) + { + LOGTEXT2(_L8("\terr = %d"), err); + // There was an attachment failure, so we just increment the count of + // attachment failures. + ASSERT_DEBUG(iEventQueue); + iEventQueue->AttachmentFailure(err); + // If we failed the attachment phase, we can't try to load drivers for + // the device. + + } + else + { + // This function always moves the 'driver loading' event from the + // device proxy created by HandleDeviceAttachmentL to the event queue. + // This event object is always populated with the correct status and + // error. + ASSERT_DEBUG(device); + DoDriverLoading(*device); + } + + // Finally, clean up the collection of information on the device's + // interfaces which was populated (maybe only partly) in + // HandleDeviceAttachmentL. + iCurrentDevice = NULL; + iInterfaces.ResetAndDestroy(); + } + +// This does the 'device attachment' phase of the new device attachment only. +void CFdf::HandleDeviceAttachmentL(TUint aDeviceId, CDeviceProxy*& aDevice) + { + LOG_FUNC + + // Create the device proxy + aDevice = CDeviceProxy::NewL(iHubDriver, aDeviceId); + CleanupStack::PushL(aDevice); + iCurrentDevice = aDevice; + // Get necessary descriptors (for this phase) + LEAVEIFERRORL(aDevice->GetDeviceDescriptor(iDD)); + LOGTEXT2(_L8("\tiDD.USBBcd = 0x%04x"), iDD.USBBcd()); + LOGTEXT2(_L8("\tiDD.DeviceClass = 0x%02x"), iDD.DeviceClass()); + LOGTEXT2(_L8("\tiDD.DeviceSubClass = 0x%02x"), iDD.DeviceSubClass()); + LOGTEXT2(_L8("\tiDD.DeviceProtocol = 0x%02x"), iDD.DeviceProtocol()); + LOGTEXT2(_L8("\tiDD.MaxPacketSize0 = %d"), iDD.MaxPacketSize0()); + LOGTEXT2(_L8("\tiDD.VendorId = 0x%04x"), iDD.VendorId()); + LOGTEXT2(_L8("\tiDD.ProductId = 0x%04x"), iDD.ProductId()); + LOGTEXT2(_L8("\tiDD.DeviceBcd = 0x%04x"), iDD.DeviceBcd()); + LOGTEXT2(_L8("\tiDD.ManufacturerIndex = %d"), iDD.ManufacturerIndex()); + LOGTEXT2(_L8("\tiDD.ProductIndex = %d"), iDD.ProductIndex()); + LOGTEXT2(_L8("\tiDD.SerialNumberIndex = %d"), iDD.SerialNumberIndex()); + LOGTEXT2(_L8("\tiDD.NumConfigurations = %d"), iDD.NumConfigurations()); + LEAVEIFERRORL(aDevice->GetConfigurationDescriptor(iCD)); + LOGTEXT2(_L8("\tiCD.TotalLength = %d"), iCD.TotalLength()); + LOGTEXT2(_L8("\tiCD.NumInterfaces = %d"), iCD.NumInterfaces()); + LOGTEXT2(_L8("\tiCD.ConfigurationValue = %d"), iCD.ConfigurationValue()); + LOGTEXT2(_L8("\tiCD.ConfigurationIndex = %d"), iCD.ConfigurationIndex()); + LOGTEXT2(_L8("\tiCD.Attributes = %d"), iCD.Attributes()); + LOGTEXT2(_L8("\tiCD.MaxPower = %d"), iCD.MaxPower()); + + const TUint8 numberOfInterfaces = iCD.NumInterfaces(); + LOGTEXT2(_L8("\tnumberOfInterfaces (field in config descriptor) = %d)"), numberOfInterfaces); + if ( numberOfInterfaces == 0 ) + { + LEAVEL(KErrUsbConfigurationHasNoInterfaces); + } + + // Walk the configuration bundle. Collect information on each interface + // (its number, class, subclass and protocol). This populates iInterfaces. + ASSERT_DEBUG(iInterfaces.Count() == 0); + ASSERT_ALWAYS(iCurrentDevice); + ParseL(iCD); + + // Log iInterfaces. + const TUint interfaceCount = iInterfaces.Count(); + LOGTEXT2(_L8("\tinterfaceCount (parsed from bundle) = %d"), interfaceCount); +#ifdef __FLOG_ACTIVE + LOGTEXT(_L8("\tLogging iInterfaces:")); + for ( TUint ii = 0 ; ii < interfaceCount ; ++ii ) + { + const TInterfaceInfo* ifInfo = iInterfaces[ii]; + ASSERT_DEBUG(ifInfo); + LOGTEXT6(_L8("\t\tiInterfaces[%d]: number %d, interface class 0x%02x subclass 0x%02x protocol 0x%02x"), + ii, + ifInfo->iNumber, + ifInfo->iClass, + ifInfo->iSubclass, + ifInfo->iProtocol + ); + } +#endif + + // Check that the config's NumInterfaces is the same as the actual number + // of interface descriptors we found. We rely on this later on. + if ( numberOfInterfaces != interfaceCount ) + { + LEAVEL(KErrUsbInterfaceCountMismatch); + } + + // Check that each interface number in iInterfaces is unique. + if ( interfaceCount > 1 ) + { + for ( TUint ii = 0 ; ii < interfaceCount ; ++ii ) + { + const TInterfaceInfo* lhs = iInterfaces[ii]; + ASSERT_DEBUG(lhs); + for ( TUint jj = ii+1 ; jj < interfaceCount ; ++jj ) + { + const TInterfaceInfo* rhs = iInterfaces[jj]; + ASSERT_DEBUG(rhs); + if ( lhs->iNumber == rhs->iNumber ) + { + LEAVEL(KErrUsbDuplicateInterfaceNumbers); + } + } + } + } + +#ifndef __OVER_DUMMYUSBDI__ + // If we're using the DummyUSBDI we don't need the real USBDI. + // Load USBDI when attached devices goes from 0 to 1 + if (iDevices.IsEmpty()) + { + TInt err = User::LoadLogicalDevice(KDriverUsbdiLddFileName); + if ( err != KErrAlreadyExists ) + { + LEAVEIFERRORL(err); + } + } +#endif // __OVER_DUMMYUSBDI__ + + // Now we know we've succeeded with a device attachment, remove the device + // proxy from the cleanup stack and put it on the TSglQue. + CLEANUPSTACK_POP1(aDevice); + iDevices.AddLast(*aDevice); + // Also put an event on the event queue. + TDeviceEvent* const attachmentEvent = aDevice->GetAttachmentEventObject(); + ASSERT_DEBUG(attachmentEvent); + attachmentEvent->iInfo.iVid = iDD.VendorId(); + attachmentEvent->iInfo.iPid = iDD.ProductId(); + attachmentEvent->iInfo.iError = KErrNone; + ASSERT_DEBUG(iEventQueue); + iEventQueue->AddDeviceEvent(*attachmentEvent); + LOGTEXT2(_L8("***USB HOST STACK: SUCCESSFUL ATTACHMENT OF DEVICE (id %d)"), aDeviceId); + } + +void CFdf::DoDriverLoading(CDeviceProxy& aDevice) + { + LOG_FUNC + + // Leaving or returning from DoDriverLoadingL is the trigger to put the + // 'driver loading' event object on the event queue. It must already have + // been populated correctly (the actual error code it left with doesn't + // feed into the driver loading event). + TRAP_IGNORE(DoDriverLoadingL(aDevice)); + + TDeviceEvent* const driverLoadingEvent = aDevice.GetDriverLoadingEventObject(); + ASSERT_DEBUG(driverLoadingEvent); + // The driver loading event object says whether driver loading succeeded + // (all interfaces were claimed without error), partly succeeded (not all + // interfaces were claimed without error), or failed (no interfaces were + // claimed without error). This information is intended for USBMAN so it + // can tell the user, but we also use it now to suspend the device if + // driver loading failed completely. + if ( driverLoadingEvent->iInfo.iDriverLoadStatus == EDriverLoadFailure ) + { + // We can't do anything with error here. Suspending the device is for + // power-saving reasons and is not critical. + (void)aDevice.Suspend(); + } + ASSERT_DEBUG(iEventQueue); + iEventQueue->AddDeviceEvent(*driverLoadingEvent); + } + + +void CFdf::DoDriverLoadingL(CDeviceProxy& aDevice) + { + LOG_FUNC + + // Check whether driver loading is enabled. + if ( !iDriverLoadingEnabled ) + { + // Complete driver load failure scenario. + aDevice.SetDriverLoadingEventData(EDriverLoadFailure, KErrUsbDriverLoadingDisabled); + LEAVEL(KErrGeneral); + } + + + // Set this member up so that when the FDC calls TokenForInterface we call + // the right proxy object. + + TInt collectedErr = KErrNone; + TBool anySuccess = EFalse; + + + // Now actually try to load the drivers. + // Device drivers are located based upon descriptor information from the USB device. The first search is + // based on information from the device descriptor and looks for a driver that matches the whole device; + // the second search is based upon locating a driver for each interface within a configuration. + // The particular keys used in the driver search are defined in the Universal Serial Bus Common Class + // Specification version 1.0. They are represented by TDeviceSearchKeys and TInterfaceSearchKeys. + // + // First perform a device search by iterating through the keys in TDeviceSearchKeys looking for a matching driver. + TBool functionDriverFound = SearchForADeviceFunctionDriverL(aDevice, anySuccess, collectedErr); + + // When do the parsing against the CD bundle, we already know if there is IAD(Interface Association Descriptor) + // in the new attached device. Once we finished the device level searching of FDC and we couldn't find any, we + // break down the loading process + if (aDevice.HasIADFlag() && !functionDriverFound) + { + aDevice.SetDriverLoadingEventData(EDriverLoadFailure, KErrUsbUnsupportedDevice); + LEAVEL(KErrGeneral); + } + // If a device FD is found then it is supposed to claim all the interfaces, if it didn't then report + // a partial success but don't offer unclaimed interfaces to any other FD. + const TUint interfaceCount = iInterfaces.Count(); + + + + // If no device driver was found then next perform an Interface search + if (!functionDriverFound) + SearchForInterfaceFunctionDriversL(aDevice, anySuccess, collectedErr); + + // Now worry about the following: + // (a) are there any unclaimed interfaces remaining? + // (b) what's in collectedErr? + // Whether all interfaces were taken, some, or none, collectedErr may have + // an error in it or KErrNone. We use specific error codes in some cases. + TUint unclaimedInterfaces = UnclaimedInterfaceCount(); + LOGTEXT2(_L8("\tunclaimedInterfaces = %d"), unclaimedInterfaces); + LOGTEXT2(_L8("\tanySuccess = %d"), anySuccess); + LOGTEXT2(_L8("\tcollectedErr = %d"), collectedErr); + ASSERT_DEBUG(unclaimedInterfaces <= interfaceCount); + + if(iDeviceDetachedTooEarly) + { + LOGTEXT(_L8("\tDevice has been detached too early!")); + iDeviceDetachedTooEarly = EFalse; + // the choice of having the status to be EDriverLoadPartialSuccess + // was not to clash with trying to suspend the device because + // of a total failure to load the FD.(because device is detached) + // even though that a FDC has been created + // see the : + // if ( driverLoadingEvent->iInfo.iDriverLoadStatus == EDriverLoadFailure ) + // in function above => void CFdf::DoDriverLoadingL(etc...) + aDevice.SetDriverLoadingEventData(EDriverLoadPartialSuccess, KErrUsbDeviceDetachedDuringDriverLoading); + } + else + { + SetFailureStatus(unclaimedInterfaces, interfaceCount, anySuccess, collectedErr, aDevice); + }// iDeviceDetachedTooEarly + + } + +// Recursive function, originally called with the configuration descriptor. +// Builds up information on the interface descriptors in the configuration +// bundle. +void CFdf::ParseL(TUsbGenericDescriptor& aDesc) + { + LOG_FUNC + LOGTEXT2(_L8("\t&aDesc = 0x%08x"), &aDesc); + LOGTEXT2(_L8("\taDesc.ibDescriptorType = %d"), aDesc.ibDescriptorType); + LOGTEXT2(_L8("\taDesc.iFirstChild = 0x%08x"), aDesc.iFirstChild); + LOGTEXT2(_L8("\taDesc.iNextPeer = 0x%08x"), aDesc.iNextPeer); + + if ( aDesc.ibDescriptorType == EInterface ) + { + // Add interface information to collection, but only if it's alternate + // setting 0. + const TUsbInterfaceDescriptor& ifDesc = static_cast(aDesc); + if ( ifDesc.AlternateSetting() == 0 ) // hard-coded '0' means the default (initial configuration) setting + { + LOGTEXT2(_L8("\tifDesc.InterfaceNumber = %d"), ifDesc.InterfaceNumber()); + LOGTEXT2(_L8("\tifDesc.NumEndpoints = %d"), ifDesc.NumEndpoints()); + LOGTEXT2(_L8("\tifDesc.InterfaceClass = 0x%02x"), ifDesc.InterfaceClass()); + LOGTEXT2(_L8("\tifDesc.InterfaceSubClass = 0x%02x"), ifDesc.InterfaceSubClass()); + LOGTEXT2(_L8("\tifDesc.InterfaceProtocol = 0x%02x"), ifDesc.InterfaceProtocol()); + LOGTEXT2(_L8("\tifDesc.Interface = %d"), ifDesc.Interface()); + + TInterfaceInfo* ifInfo = TInterfaceInfo::NewL(iInterfaces); + ifInfo->iNumber = ifDesc.InterfaceNumber(); + ifInfo->iClass = ifDesc.InterfaceClass(); + ifInfo->iSubclass = ifDesc.InterfaceSubClass(); + ifInfo->iProtocol = ifDesc.InterfaceProtocol(); + ifInfo->iClaimed = EFalse; + } + } + else if (!iCurrentDevice->HasIADFlag() && aDesc.ibDescriptorType == EInterfaceAssociation) + { + // When found a Interface association descriptor, set this flag to ETrue, + // it is checked later after the device level driverloading. + iCurrentDevice->SetHasIADFlag(); + } + else if (aDesc.ibDescriptorType == EOTG) + { + // OTG descriptor found + const TUsbOTGDescriptor& otgDesc = static_cast(aDesc); + + LOGTEXT2(_L8("\totgDesc.Attributes = %b"), otgDesc.Attributes()); + LOGTEXT2(_L8("\totgDesc.HNPSupported = %d"), otgDesc.HNPSupported()); + LOGTEXT2(_L8("\totgDesc.SRPSupported = %d"), otgDesc.SRPSupported()); + + iCurrentDevice->SetOtgDescriptorL(otgDesc); + } + + TUsbGenericDescriptor* const firstChild = aDesc.iFirstChild; + if ( firstChild ) + { + ParseL(*firstChild); + } + + TUsbGenericDescriptor* const nextPeer = aDesc.iNextPeer; + if ( nextPeer ) + { + ParseL(*nextPeer); + } + } + +// Method that uses only one array to hold the unclaimed interface numbers. +void CFdf::FindDriversForInterfacesUsingSpecificKeyL(CDeviceProxy& aDevice, + TInt& aCollectedErr, + TBool& aAnySuccess, + RArray& aInterfacesNumberArray, + TInterfaceSearchKeys aKey) + { + LOG_FUNC + + const TUint interfaceCount = iInterfaces.Count(); + for ( TUint ii = 0 ; ii < interfaceCount ; ++ii ) + { + TInterfaceInfo* ifInfo = iInterfaces[ii]; + ASSERT_DEBUG(ifInfo); + + if ((ifInfo->iClaimed) || + (aKey == EVendorInterfacesubclassInterfaceprotocol && ifInfo->iClass != KVendorSpecificInterfaceClassValue)|| + (aKey == EVendorInterfacesubclass && ifInfo->iClass != KVendorSpecificInterfaceClassValue) || + (aKey == EInterfaceclassInterfacesubclassInterfaceprotocol && ifInfo->iClass == KVendorSpecificInterfaceClassValue) || + (aKey == EInterfaceclassInterfacesubclass && ifInfo->iClass == KVendorSpecificInterfaceClassValue)) + { + continue; + } + + + TBuf8 searchKey; + FormatInterfaceSearchKey(searchKey, aKey, *ifInfo); + + LOGTEXT2(_L8("\tsearchKey = \"%S\""), &searchKey); + // RArray* array = &aInterfacesNumberArray; + + FindDriverForInterfaceUsingSpecificKey(aDevice, aCollectedErr, aAnySuccess, aInterfacesNumberArray, searchKey); + + // Putting ii+1 as the starting offset is to remove the interface on which + // the searching have been done. + RebuildUnClaimedInterfacesArrayL(aDevice, aInterfacesNumberArray, ii+1); + } + } + + + +// Called for one interface, to find a Function Driver on the basis of a + +// specific search key. +void CFdf::FindDriverForInterfaceUsingSpecificKey(CDeviceProxy& aDevice, + TInt& aCollectedErr, + TBool& aAnySuccess, + RArray& aInterfacesGivenToFdc, + const TDesC8& aSearchKey) + { + + LOG_FUNC + LOGTEXT2(_L8("\taSearchKey = \"%S\""), &aSearchKey); + + // Find an FDC matching this search key. + TSglQueIter iter(iFunctionDrivers); + iter.SetToFirst(); + CFdcProxy* fdc; + + while ( ( fdc = iter++ ) != NULL ) + { + LOGTEXT2(_L8("\tFDC's default_data field = \"%S\""), &fdc->DefaultDataField()); +#ifdef _DEBUG + // having these two together in the debug window is helpful for interactive debugging + TBuf8 fd_key; + fd_key.Append(fdc->DefaultDataField().Ptr(), fdc->DefaultDataField().Length() > KMaxSearchKeyLength ? KMaxSearchKeyLength : fdc->DefaultDataField().Length()); + TBuf8 searchKey; + searchKey.Append(aSearchKey.Ptr(), aSearchKey.Length() > KMaxSearchKeyLength ? KMaxSearchKeyLength : aSearchKey.Length()); + TInt version = fdc->Version(); +#endif // _DEBUG + if (aSearchKey.CompareF(fdc->DefaultDataField()) == 0 && !fdc->MarkedForDeletion()) + { + // If there is more than one matching FD then if all of them are in RAM we simply choose the first one we find. + // (Similarly if they are all in ROM we choose the first one although this situation should not arise as a device + // manufacturer should not put two matching FDs into ROM). + // However if there are matching FDs in ROM and RAM then the one in ROM should be selected in preference to + // any in RAM. Hence at this point if the matching FD we have found is in RAM then we need to scan the list + // of FDs to see if there is also a matching one in ROM and if so we'll skip this iteration of the loop. + + // Edwin comment + // Put the searching key and the iterator as the parameter of + // searching if more FDCs have the same default_data. The iterator + // helps to searching from the current FDC since this is the very first + // suitable FDC we found so fa. + if (!aDevice.MultipleDriversFlag() && FindMultipleFDs(aSearchKey, iter)) + { + aDevice.SetMultipleDriversFlag(); + } + + LOGTEXT2(_L8("\tfound matching FDC (0x%08x)"), fdc); +#ifdef __FLOG_ACTIVE + const TUint count = aInterfacesGivenToFdc.Count(); + LOGTEXT2(_L8("\tlogging aInterfacesGivenToFdc (interfaces being offered to the FDC): count = %d"), count); + for ( TUint ii = 0 ; ii < count ; ++ii ) + { + LOGTEXT3(_L8("\t\tindex %d: interface number %d"), ii, aInterfacesGivenToFdc[ii]); + } +#endif + TInt err = fdc->NewFunction(aDevice.DeviceId(), aInterfacesGivenToFdc, iDD, iCD); + LOGTEXT2(_L8("\tNewFunction returned %d"), err); + // To correctly determine whether the driver load for the whole + // configuration was a complete failure, a partial success or a + // complete success, we need to collect any non-KErrNone error + // from this, and whether any handovers worked at all. + if ( err == KErrNone ) + { +#ifdef __FLOG_ACTIVE + LOGTEXT3(_L8("***USB HOST STACK: THE FOLLOWING INTERFACES OF DEVICE %d WERE SUCCESSFULLY PASSED TO FUNCTION DRIVER WITH IMPL UID 0x%08x"), + aDevice.DeviceId(), fdc->ImplUid()); + // We want to log each interface that's in + // aInterfacesGivenToFdc AND is marked claimed in iInterfaces. + for ( TUint ii = 0 ; ii < aInterfacesGivenToFdc.Count() ; ++ii ) + { + const TUint ifNum = aInterfacesGivenToFdc[ii]; + for ( TUint jj = 0 ; jj < iInterfaces.Count() ; ++jj ) + { + const TInterfaceInfo* ifInfo = iInterfaces[jj]; + ASSERT_DEBUG(ifInfo); + if ( ifNum == ifInfo->iNumber + && ifInfo->iClaimed + ) + { + LOGTEXT2(_L8("***USB HOST STACK: bInterfaceNumber %d"), ifNum); + } + } + } +#endif + aAnySuccess = ETrue; + } + else + { + aCollectedErr = err; + } + // We found a matching FDC for this interface- no need to look for more. + break; + } + } + } + +void CFdf::HandleDeviceDetachment(TUint aDeviceId) + { + LOG_FUNC + LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); + + +#ifdef _DEBUG + TBool found = EFalse; +#endif + // Find the relevant device proxy. If there isn't one, just drop the + // notification, assuming that the corresponding attachment failed at the + // FDF level. + TSglQueIter iter(iDevices); + iter.SetToFirst(); + CDeviceProxy* device; + while ( ( device = iter++ ) != NULL ) + { + if ( device->DeviceId() == aDeviceId ) + { +#ifdef _DEBUG + found = ETrue; +#endif + LOGTEXT(_L8("\tfound matching device proxy")); + + iDevices.Remove(*device); + // Before destroying the device proxy, take the detachment event + // stored in it for the event queue. + TDeviceEvent* const detachmentEvent = device->GetDetachmentEventObject(); + ASSERT_DEBUG(detachmentEvent); + ASSERT_DEBUG(iEventQueue); + iEventQueue->AddDeviceEvent(*detachmentEvent); + LOGTEXT2(_L8("***USB HOST STACK: DETACHMENT OF DEVICE (id %d)"), aDeviceId); + delete device; + + TellFdcsOfDeviceDetachment(aDeviceId); + +#ifndef __OVER_DUMMYUSBDI__ + // If we're using the DummyUSBDI the real USBDI isn't loaded. + // Unload USBDI when attached devices goes from 1 to 0 + if (iDevices.IsEmpty()) + { + TInt err = User::FreeLogicalDevice(KDriverUsbdiLddFileName); + LOGTEXT2(_L8("\tFreeLogicalDevice( usbdi ) returned %d"), err); + } +#endif // __OVER_DUMMYUSBDI__ + + break; + } + } + +#ifdef _DEBUG + if ( !found ) + { + LOGTEXT(_L8("\tno matching device proxy found")); + } +#endif + } + +void CFdf::HandleDevmonEvent(TInt aEvent) + { + LOG_FUNC + LOGTEXT2(_L8("\taEvent = %d"), aEvent); + + ASSERT_DEBUG(iEventQueue); + iEventQueue->AddDevmonEvent(aEvent); + } + +void CFdf::TellFdcsOfDeviceDetachment(TUint aDeviceId) + { + LOG_FUNC + LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); + + TSglQueIter iter(iFunctionDrivers); + iter.SetToFirst(); + CFdcProxy* fdc; + while ( ( fdc = iter++ ) != NULL ) + { + fdc->DeviceDetached(aDeviceId); + if (fdc->DeviceCount() == 0 && fdc->MarkedForDeletion()) + { // If the FDC was uninstalled while it was in use then it couldn't be deleted at that point so delete it now + iFunctionDrivers.Remove(*fdc); + delete fdc; + } + } + + } + +TUint32 CFdf::TokenForInterface(TUint8 aInterface) + { + LOG_FUNC + LOGTEXT2(_L8("\taInterface = %d"), aInterface); + TUint32 token = 0; + + // Check that the interface was in the array given to the FD and mark it + // as claimed. + TBool found = EFalse; + const TUint interfaceCount = iInterfaces.Count(); + for ( TUint ii = 0 ; ii < interfaceCount ; ++ii ) + { + TInterfaceInfo* ifInfo = iInterfaces[ii]; + ASSERT_DEBUG(ifInfo); + if ( ifInfo->iNumber == aInterface ) + { + found = ETrue; + // The FDC tried to claim an interface that was already claimed. + ASSERT_ALWAYS(!ifInfo->iClaimed); + ifInfo->iClaimed = ETrue; + break; + } + } + // Could not find interface in the interface array- the FDC tried to claim + // an interface it had not been offered. + ASSERT_ALWAYS(found); + + ASSERT_DEBUG(iCurrentDevice); + + // GetTokenForInterface will return error in the following cases: + // 1/ KErrBadHandle: invalid device handle (the CDeviceProxy asserts that + // the handle is valid) because the device has been detached while processing + // may be due to too much current or cable has been removed + // so FDF will still return a token of 0 and FDF will handle the proper + // device detachment when it will be able to process the detachment notification + // + // 2/ KErrNotFound: interface not found (if this happens, the FDC has + // misbehaved, and the correct thing to do is to panic) + // 3/ KErrInUse: we've already requested a token for that interface + // (ditto) + // 4/ KErrOverflow: when 0xFFFFFFFF tokens have been requested (this is a + // realistic built-in limitation of USBD) + + + TInt err = iCurrentDevice->GetTokenForInterface(aInterface, token); + switch(err) + { + case KErrBadHandle: + token = 0; + iDeviceDetachedTooEarly = ETrue; + + case KErrNone: // Fall through and do nothing + break; + + default: + LOGTEXT3(_L8("\tUnexpected error %d when requesting token for aInterface %d"),err,aInterface); + ASSERT_ALWAYS(0); + break; + } + + LOGTEXT3(_L8("\tToken for interface %d is = %d"),aInterface, token); + + return token; + } + +CDeviceProxy* CFdf::DeviceProxyL(TUint aDeviceId) const + { + LOG_FUNC + LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); + + TSglQueIter iter(const_cast(this)->iDevices); + iter.SetToFirst(); + CDeviceProxy* device = NULL; + while ( ( device = iter++ ) != NULL ) + { + if ( device->DeviceId() == aDeviceId ) + { + LOGTEXT2(_L8("\tdevice = 0x%08x"), device); + return device; + } + } + LEAVEL(KErrNotFound); + return NULL; // avoid warning + } + +const RArray& CFdf::GetSupportedLanguagesL(TUint aDeviceId) const + { + LOG_FUNC + LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); + + CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId); + return deviceProxy->GetSupportedLanguages(); + } + +void CFdf::GetManufacturerStringDescriptorL(TUint aDeviceId, TUint32 aLangId, TName& aString) const + { + LOG_FUNC + LOGTEXT3(_L8("\taDeviceId = %d, aLangId = 0x%04x"), aDeviceId, aLangId); + + CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId); + deviceProxy->GetManufacturerStringDescriptorL(aLangId, aString); + LOGTEXT2(_L("\taString = \"%S\""), &aString); + } + +void CFdf::GetProductStringDescriptorL(TUint aDeviceId, TUint32 aLangId, TName& aString) const + { + LOG_FUNC + LOGTEXT3(_L8("\taDeviceId = %d, aLangId = 0x%04x"), aDeviceId, aLangId); + + CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId); + deviceProxy->GetProductStringDescriptorL(aLangId, aString); + LOGTEXT2(_L("\taString = \"%S\""), &aString); + } + +void CFdf::GetOtgDeviceDescriptorL(TInt aDeviceId, TOtgDescriptor& aDescriptor) const + { + LOG_FUNC + + DeviceProxyL(aDeviceId)->GetOtgDescriptorL(aDescriptor); + } + +void CFdf::GetSerialNumberStringDescriptorL(TUint aDeviceId, TUint32 aLangId, TName& aString) const + { + LOG_FUNC + LOGTEXT3(_L8("\taDeviceId = %d, aLangId = 0x%04x"), aDeviceId, aLangId); + + CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId); + deviceProxy->GetSerialNumberStringDescriptorL(aLangId, aString); + LOGTEXT2(_L("\taString = \"%S\""), &aString); + } + +void CFdf::SearchForInterfaceFunctionDriversL(CDeviceProxy& aDevice, TBool& aAnySuccess, TInt& aCollectedErr) + { + RArray interfacesNumberArray; + CleanupClosePushL(interfacesNumberArray); + + + + for ( TUint ii = 0 ; ii < iInterfaces.Count() ; ++ii ) + { + // At this point we have NOT done any interface level searching yet, + // and all interfaces should in the Unclaimed status, + // just simply put them all into the interfacesNumberArray. + TUint interfaceNumber = iInterfaces[ii]->iNumber; + AppendInterfaceNumberToArrayL(aDevice, interfacesNumberArray, interfaceNumber); + } + + + for ( TUint key = EVendorProductDeviceConfigurationvalueInterfacenumber ; key < EMaxInterfaceSearchKey ; ++key ) + { + // Searching for proper FDCs based on different criteria. + FindDriversForInterfacesUsingSpecificKeyL(aDevice, + aCollectedErr, + aAnySuccess, + interfacesNumberArray, + (TInterfaceSearchKeys) key); + + // If all the interfaces have been claimed by an FD then there is no point searching for other FDs + if (UnclaimedInterfaceCount() == 0) + { + break; + } + else + { + // Put all the unclaimed interface numbers into the array again. + RebuildUnClaimedInterfacesArrayL(aDevice, interfacesNumberArray); + } + } + CleanupStack::PopAndDestroy(&interfacesNumberArray); + } +void CFdf::RebuildUnClaimedInterfacesArrayL(CDeviceProxy& aDevice, RArray& aArray, TUint aOffset) + { + aArray.Reset(); + for ( TUint ii = aOffset ; ii < iInterfaces.Count() ; ++ii ) + { + if (!iInterfaces[ii]->iClaimed) + { + TUint interfaceNumber = iInterfaces[ii]->iNumber; + AppendInterfaceNumberToArrayL(aDevice, aArray, interfaceNumber); + } + } + } + +void CFdf::AppendInterfaceNumberToArrayL(CDeviceProxy& aDevice, RArray& aArray, TUint aInterfaceNo) const + { + TInt err = aArray.Append(aInterfaceNo); + if ( err ) + { + aDevice.SetDriverLoadingEventData(EDriverLoadFailure, err); + LEAVEL(err); + } + } + + + +TBool CFdf::SearchForADeviceFunctionDriverL(CDeviceProxy& aDevice, TBool& aAnySuccess, TInt& aCollectedErr) + { + + RArray interfaces; + CleanupClosePushL(interfaces); + + for (TUint ii = 0; ii < iInterfaces.Count(); ++ii) + { + TUint interfaceNumber = iInterfaces[ii]->iNumber; + AppendInterfaceNumberToArrayL(aDevice, interfaces, interfaceNumber); + } + + TBool foundFdc = EFalse; + for (TUint key = EVendorProductDevice; key < EMaxDeviceSearchKey; ++key) + { + + if (key == EVendorDevicesubclassDeviceprotocol && iDD.DeviceClass() != KVendorSpecificDeviceClassValue) + continue; + if (key == EVendorDevicesubclass && iDD.DeviceClass() != KVendorSpecificDeviceClassValue) + continue; + if (key == EDeviceclassDevicesubclassDeviceprotocol && iDD.DeviceClass() == KVendorSpecificDeviceClassValue) + continue; + if (key == EDeviceclassDevicesubclass && iDD.DeviceClass() == KVendorSpecificDeviceClassValue) + continue; + + TBuf8 searchKeyString; + FormatDeviceSearchKey(searchKeyString, (TDeviceSearchKeys)key); + + // Find an FDC matching this search key. + TSglQueIter iter(iFunctionDrivers); + iter.SetToFirst(); + CFdcProxy* fdc; + while ( ( fdc = iter++ ) != NULL) + { + if (fdc->MarkedForDeletion()) + continue; + LOGTEXT2(_L8("\tFDC's default_data field = \"%S\""), &fdc->DefaultDataField()); +#ifdef _DEBUG + // having these two together in the debug window is helpful for interactive debugging + TBuf8 fd_key; + fd_key.Append(fdc->DefaultDataField().Ptr(), fdc->DefaultDataField().Length() > KMaxSearchKeyLength ? KMaxSearchKeyLength : fdc->DefaultDataField().Length()); + TBuf8 search_key; + search_key.Append(searchKeyString.Ptr(), searchKeyString.Length() > KMaxSearchKeyLength ? KMaxSearchKeyLength : searchKeyString.Length()); + TInt version = fdc->Version(); +#endif + if (searchKeyString.CompareF(fdc->DefaultDataField()) == 0) + { + + // If there is more than one matching FD then if all of them are in RAM we simply choose the first one we find. + // (Similarly if they are all in ROM we choose the first one although this situation should not arise as a device + // manufacturer should not put two matching FDs into ROM). + // However if there are matching FDs in ROM and RAM then the one in ROM should be selected in preference to + // any in RAM. Hence at this point if the matching FD we have found is in RAM then we need to scan the list + // of FDs to see if there is also a matching one in ROM and if so we'll skip this iteration of the loop. + //if (!fdc->RomBased() && FindMatchingRomBasedFD(searchKeyString)) + // continue; + if (FindMultipleFDs(searchKeyString, iter)) + { + aDevice.SetMultipleDriversFlag(); + } + + foundFdc = ETrue; + LOGTEXT2(_L8("\tfound matching FDC (0x%08x)"), fdc); + TInt err = fdc->NewFunction(aDevice.DeviceId(), interfaces, iDD, iCD); + LOGTEXT2(_L8("\tNewFunction returned %d"), err); + // To correctly determine whether the driver load for the whole + // configuration was a complete failure, a partial success or a + // complete success, we need to collect any non-KErrNone error + // from this, and whether any handovers worked at all. + if ( err == KErrNone ) + { + aAnySuccess = ETrue; + } + else + { + aCollectedErr = err; + } + break; // We found a matching FDC so no need to look for more. + } + } + if (foundFdc) + break; + } // end of for + CleanupStack::PopAndDestroy(&interfaces); + return foundFdc; + + } // end of function + + + + +// +// Search the list of FDs looking for which matches with aSearchKey and is rom based and return true if found. +// +// added for Multiple FDs +TBool CFdf::FindMultipleFDs(const TDesC8& aSearchKey,TSglQueIter& aFdcIter) + { + CFdcProxy* fdc; + while ( ( fdc = aFdcIter++ ) != NULL) + { + if (!fdc->MarkedForDeletion() && (aSearchKey.CompareF(fdc->DefaultDataField()) == 0)) + return ETrue; + } + + return EFalse; + } + +// +// Format the string aSearchKey according to aSearchKeys to search for Device Functions drivers +// +void CFdf::FormatDeviceSearchKey(TDes8& aSearchKey, TDeviceSearchKeys aDeviceSearchKeys) + { + LOG_FUNC + switch (aDeviceSearchKeys) + { + case EVendorProductDevice: + { + _LIT8(KTemplateV_P_D, "V0x%04xP0x%04xD0x%04x"); + aSearchKey.Format(KTemplateV_P_D(), iDD.VendorId(), iDD.ProductId(), iDD.DeviceBcd()); + break; + } + case EVendorProduct: + { + _LIT8(KTemplateV_P, "V0x%04xP0x%04x"); + aSearchKey.Format(KTemplateV_P(), iDD.VendorId(), iDD.ProductId()); + break; + } + case EVendorDevicesubclassDeviceprotocol: + { + _LIT8(KTemplateV_DSC_DP, "V0x%04xDSC0x%02xDP0x%02x"); + aSearchKey.Format(KTemplateV_DSC_DP(), iDD.VendorId(), iDD.DeviceSubClass(), iDD.DeviceProtocol()); + break; + } + case EVendorDevicesubclass: + { + _LIT8(KTemplateV_DSC, "V0x%04xDSC0x%02x"); + aSearchKey.Format(KTemplateV_DSC(), iDD.VendorId(), iDD.DeviceSubClass()); + break; + } + case EDeviceclassDevicesubclassDeviceprotocol: + { + _LIT8(KTemplateDC_DSC_DP, "DC0x%02xDSC0x%02xDP0x%02x"); + aSearchKey.Format(KTemplateDC_DSC_DP(), iDD.DeviceClass(), iDD.DeviceSubClass(), iDD.DeviceProtocol()); + break; + } + case EDeviceclassDevicesubclass: + { + _LIT8(KTemplateDC_DSC, "DC0x%02xDSC0x%02x"); + aSearchKey.Format(KTemplateDC_DSC(), iDD.DeviceClass(), iDD.DeviceSubClass()); + break; + } + default: + { + ASSERT_DEBUG(EFalse); + } + } + + LOGTEXT2(_L8("\taSearchKey = \"%S\""), &aSearchKey); + } + + + + + +// +// Format the string aSearchKey according to aSearchKeys to search for Interface Functions drivers +// +void CFdf::FormatInterfaceSearchKey(TDes8& aSearchKey, TInterfaceSearchKeys aSearchKeys, const TInterfaceInfo& aIfInfo) + { + LOG_FUNC + switch (aSearchKeys) + { + case EVendorProductDeviceConfigurationvalueInterfacenumber: + { + _LIT8(KTemplateV_P_D_CV_IN, "V0x%04xP0x%04xD0x%04xCV0x%02xIN0x%02x"); + aSearchKey.Format(KTemplateV_P_D_CV_IN(), iDD.VendorId(), iDD.ProductId(), iDD.DeviceBcd(), iCD.ConfigurationValue(), aIfInfo.iNumber); + break; + } + case EVendorProductConfigurationValueInterfacenumber: + { + _LIT8(KTemplateV_P_CV_IN, "V0x%04xP0x%04xCV0x%02xIN0x%02x"); + aSearchKey.Format(KTemplateV_P_CV_IN(), iDD.VendorId(), iDD.ProductId(), iCD.ConfigurationValue(), aIfInfo.iNumber); + break; + } + case EVendorInterfacesubclassInterfaceprotocol: + { + _LIT8(KTemplateV_ISC_IP, "V0x%04xISC0x%02xIP0x%02x"); + aSearchKey.Format(KTemplateV_ISC_IP(), iDD.VendorId(), aIfInfo.iSubclass, aIfInfo.iProtocol); + break; + } + case EVendorInterfacesubclass: + { + _LIT8(KTemplateV_ISC, "V0x%04xISC0x%02x"); + aSearchKey.Format(KTemplateV_ISC(), iDD.VendorId(), aIfInfo.iSubclass); + break; + } + case EInterfaceclassInterfacesubclassInterfaceprotocol: + { + _LIT8(KTemplateIC_ISC_IP, "IC0x%02xISC0x%02xIP0x%02x"); + aSearchKey.Format(KTemplateIC_ISC_IP(), aIfInfo.iClass, aIfInfo.iSubclass, aIfInfo.iProtocol); + break; + } + case EInterfaceclassInterfacesubclass: + { + _LIT8(KTemplateIC_ISC, "IC0x%02xISC0x%02x"); + aSearchKey.Format(KTemplateIC_ISC(), aIfInfo.iClass, aIfInfo.iSubclass); + break; + } + default: + { + ASSERT_DEBUG(EFalse); + } + } + LOGTEXT2(_L8("\taSearchKey = \"%S\""), &aSearchKey); + } + + +TUint CFdf::UnclaimedInterfaceCount() const + { + LOG_FUNC + TUint unclaimedInterfaces = 0; + for ( TUint ii = 0 ; ii < iInterfaces.Count() ; ++ii ) + { + TInterfaceInfo* ifInfo = iInterfaces[ii]; + ASSERT_DEBUG(ifInfo); + if ( !ifInfo->iClaimed ) + { + LOGTEXT2(_L8("\tunclaimed interface: ifInfo->iNumber = %d"), ifInfo->iNumber); + ++unclaimedInterfaces; + } + } + LOGTEXT2(_L("\tunclaimedInterfaces = \"%d\""), unclaimedInterfaces); + return unclaimedInterfaces; + } + + +void CFdf::SetFailureStatus(TInt aUnclaimedInterfaces, TInt aInterfaceCount, TBool aAnySuccess, TBool aCollectedErr, CDeviceProxy& aDevice) + { + const TUint KMultipleDriverFound = aDevice.MultipleDriversFlag()?KMultipleDriversFound : 0; + + if (aUnclaimedInterfaces) + { + if(aUnclaimedInterfaces == aInterfaceCount) + { + // complete failure + aDevice.SetDriverLoadingEventData((TDriverLoadStatus)(EDriverLoadFailure|KMultipleDriverFound), KErrUsbFunctionDriverNotFound); + } + else + {// at that stage because we have unclaimed interfaces it means that + // depending on anySuccess we have a failure or a partial success + TDriverLoadStatus status = (aAnySuccess)? EDriverLoadPartialSuccess:EDriverLoadFailure; + aDevice.SetDriverLoadingEventData((TDriverLoadStatus)(status|KMultipleDriverFound), KErrUsbFunctionDriverNotFound); + } + } + else + { + if (aCollectedErr) + { + // There were no unclaimed interfaces, but an error was expressed. + // This is either a partial success or a complete failure scenario. + TDriverLoadStatus status = aAnySuccess ? EDriverLoadPartialSuccess : EDriverLoadFailure; + aDevice.SetDriverLoadingEventData((TDriverLoadStatus)(status|KMultipleDriverFound), aCollectedErr); + } + else + { + // There were no unclaimed interfaces, and no error reported. + aDevice.SetDriverLoadingEventData((TDriverLoadStatus)(EDriverLoadSuccess|KMultipleDriverFound)); + } + } + } +