/*
* 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 <usb/usblogger.h>
#include "utils.h"
#include <usbhost/internal/fdcplugin.hrh>
#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<CFdf::TInterfaceInfo>& 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<CDeviceProxy> 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<CFdcProxy> 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<CFdcProxy> 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<CFdcProxy> 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<TUsbInterfaceDescriptor&>(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<TUsbOTGDescriptor&>(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<TUint>& 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))
{
// Putting ii+1 as the starting offset is to remove the interface on which the searching have been done.
RebuildUnClaimedInterfacesArrayL(aDevice, aInterfacesNumberArray, ii+1);
continue;
}
TBuf8<KMaxSearchKeyLength> searchKey;
FormatInterfaceSearchKey(searchKey, aKey, *ifInfo);
LOGTEXT2(_L8("\tsearchKey = \"%S\""), &searchKey);
// RArray<TUint>* 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<TUint>& aInterfacesGivenToFdc,
const TDesC8& aSearchKey)
{
LOG_FUNC
LOGTEXT2(_L8("\taSearchKey = \"%S\""), &aSearchKey);
// Find an FDC matching this search key.
TSglQueIter<CFdcProxy> 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<KMaxSearchKeyLength > fd_key;
fd_key.Append(fdc->DefaultDataField().Ptr(), fdc->DefaultDataField().Length() > KMaxSearchKeyLength ? KMaxSearchKeyLength : fdc->DefaultDataField().Length());
TBuf8<KMaxSearchKeyLength > 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<CDeviceProxy> 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<CFdcProxy> 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<CDeviceProxy> iter(const_cast<CFdf*>(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<TUint>& 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<TUint> 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<TUint>& 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<TUint>& 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<TUint> 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<KMaxSearchKeyLength> searchKeyString;
FormatDeviceSearchKey(searchKeyString, (TDeviceSearchKeys)key);
// Find an FDC matching this search key.
TSglQueIter<CFdcProxy> 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<KMaxSearchKeyLength> fd_key;
fd_key.Append(fdc->DefaultDataField().Ptr(), fdc->DefaultDataField().Length() > KMaxSearchKeyLength ? KMaxSearchKeyLength : fdc->DefaultDataField().Length());
TBuf8<KMaxSearchKeyLength> 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<CFdcProxy>& 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));
}
}
}