/*
* Copyright (c) 2007-2010 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"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "fdfTraces.h"
#endif
_LIT(KDriverUsbhubLddFileName,"usbhubdriver");
_LIT(KDriverUsbdiLddFileName,"usbdi");
_LIT(KPanicCategory, "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)
{
OstTraceFunctionEntry0( CFDF_TINTERFACEINFO_NEWL_ENTRY );
TInterfaceInfo* self = new(ELeave) TInterfaceInfo;
CleanupStack::PushL(self);
aInterfaces.AppendL(self);
CLEANUPSTACK_POP1(self);
OstTraceFunctionExit0( CFDF_TINTERFACEINFO_NEWL_EXIT );
return self;
}
CFdf* CFdf::NewL()
{
OstTraceFunctionEntry0( CFDF_NEWL_ENTRY );
CFdf* self = new(ELeave) CFdf;
CleanupStack::PushL(self);
self->ConstructL();
CLEANUPSTACK_POP1(self);
OstTraceFunctionExit0( CFDF_NEWL_EXIT );
return self;
}
CFdf::CFdf()
: iDevices(_FOFF(CDeviceProxy, iLink)),
iFunctionDrivers(_FOFF(CFdcProxy, iLink))
{
OstTraceFunctionEntry0( CFDF_CFDF_CONS_ENTRY );
}
void CFdf::ConstructL()
{
OstTraceFunctionEntry0( CFDF_CONSTRUCTL_ENTRY );
#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,OstTrace1( TRACE_NORMAL, CFDF_CONSTRUCTL, "Error when loading KDriverUsbhubLddFileName OVER DUMMYUSBDI; err=%d", err ););
}
#endif // __OVER_DUMMYUSBDI__
TInt errDr=iHubDriver.Open();
LEAVEIFERRORL(errDr,OstTrace1( TRACE_NORMAL, CFDF_CONSTRUCTL_DUP1, "Error when open iHubDriver; errDr=%d", errDr ););
#ifdef __OVER_DUMMYUSBDI__
//LEAVEIFERRORL(iHubDriver.StartHost());
TInt errHo=iHubDriver.StartHost();
LEAVEIFERRORL(errHo,OstTrace1( TRACE_NORMAL, CFDF_CONSTRUCTL_DUP2, "Fail in iHubDriver.StartHost in dummy; errHo=%d", errHo ););
#endif
iActiveWaitForBusEvent = CActiveWaitForBusEvent::NewL(iHubDriver, iBusEvent, *this);
iActiveWaitForBusEvent->Wait();
CreateFunctionDriverProxiesL();
iActiveWaitForEComEvent = CActiveWaitForEComEvent::NewL(*this);
iActiveWaitForEComEvent->Wait();
iEventQueue = CEventQueue::NewL(*this);
OstTraceFunctionExit0( CFDF_CONSTRUCTL_EXIT );
}
void CFdf::CreateFunctionDriverProxiesL()
{
OstTraceFunctionEntry0( CFDF_CREATEFUNCTIONDRIVERPROXIESL_ENTRY );
REComSession::ListImplementationsL(TUid::Uid(KFdcEcomInterfaceUid), iImplInfoArray);
const TUint count = iImplInfoArray.Count();
OstTrace1( TRACE_NORMAL, CFDF_CREATEFUNCTIONDRIVERPROXIESL, "\tiImplInfoArray.Count() upon FDF creation = %d", count );
#ifdef _DEBUG
if ( count == 0 )
{
OstTrace0( TRACE_NORMAL, CFDF_CREATEFUNCTIONDRIVERPROXIESL_DUP1, "\tTHERE ARE NO FUNCTION DRIVERS PRESENT IN THE SYSTEM" );
}
else
{
for (TInt32 kk = 0; kk < count; ++kk)
OstTraceExt2( TRACE_NORMAL, CFDF_CREATEFUNCTIONDRIVERPROXIESL_DUP2,
"FDC implementation UID: 0x%08x Index:%d ",
iImplInfoArray[kk]->ImplementationUid().iUid, kk);
}
#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);
}
OstTraceFunctionExit0( CFDF_CREATEFUNCTIONDRIVERPROXIESL_EXIT );
}
CFdf::~CFdf()
{
OstTraceFunctionEntry0( CFDF_CFDF_DES_ENTRY );
// Mimic the detachment of each attached device.
TSglQueIter<CDeviceProxy> deviceIter(iDevices);
deviceIter.SetToFirst();
CDeviceProxy* device;
while ( ( device = deviceIter++ ) != NULL )
{
const TUint deviceId = device->DeviceId();
OstTrace1( TRACE_NORMAL, CFDF_CFDF, "mimicking 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);
OstTrace1( TRACE_NORMAL, CFDF_CFDF_DUP1, "FreeLogicalDevice( usbhubdriver ) returned %d", err );
err = User::FreeLogicalDevice(KDriverUsbdiLddFileName);
OstTrace1( TRACE_NORMAL, CFDF_CFDF_DUP2, "FreeLogicalDevice( 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.
if(!(iInterfaces.Count() == 0))
{
OstTrace1( TRACE_FATAL, CFDF_CFDF_DUP3, "Memory leak from interface;Interface remains %d", iInterfaces.Count() );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
iImplInfoArray.ResetAndDestroy();
REComSession::FinalClose();
OstTraceFunctionExit0( CFDF_CFDF_DES_EXIT );
}
void CFdf::EnableDriverLoading()
{
OstTraceFunctionEntry0( CFDF_ENABLEDRIVERLOADING_ENTRY );
iDriverLoadingEnabled = ETrue;
}
void CFdf::DisableDriverLoading()
{
OstTraceFunctionEntry0( CFDF_DISABLEDRIVERLOADING_ENTRY );
iDriverLoadingEnabled = EFalse;
}
void CFdf::SetSession(CFdfSession* aSession)
{
OstTraceFunctionEntry0( CFDF_SETSESSION_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_SETSESSION, "aSession = 0x%08x", aSession );
iSession = aSession;
}
CFdfSession* CFdf::Session()
{
return iSession;
}
TBool CFdf::GetDeviceEvent(TDeviceEvent& aEvent)
{
OstTraceFunctionEntry0( CFDF_GETDEVICEEVENT_ENTRY );
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_GETDEVICEEVENT, "iEventQueue is empty" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
return iEventQueue->GetDeviceEvent(aEvent);
}
TBool CFdf::GetDevmonEvent(TInt& aEvent)
{
OstTraceFunctionEntry0( CFDF_GETDEVMONEVENT_ENTRY );
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_GETDEVMONEVENT, "iEventQueue is empty" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
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()
{
OstTraceFunctionEntry0( CFDF_HANDLEECOMEVENTRECEIVEDL_ENTRY );
// 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();
OstTrace1( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL, "iImplInfoArray.Count() after ECom notification= %d", implementationsCount );
if ( implementationsCount == 0 )
{
OstTrace0( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL_DUP1, "THERE ARE NO FUNCTION DRIVERS PRESENT IN THE SYSTEM" );
}
TSglQueIter<CFdcProxy> proxiesIterDebug(iFunctionDrivers);
CFdcProxy* fdcDebug = NULL;
while ( ( fdcDebug = proxiesIterDebug++ ) != NULL )
{
TUid fdcUid = fdcDebug->ImplUid();
OstTrace1( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL_DUP2, "Old FDC Proxy implementation UID: 0x%08x", fdcUid.iUid );
TInt fdcVersion = fdcDebug->Version();
OstTrace1( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL_DUP3, "FDC Proxy version UID: %d", fdcVersion );
}
OstTrace0( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL_DUP4, "------------------------------------------------------------------" );
for (TInt kk = 0; kk < implementationsCount; ++kk)
{
TUid fdcUid2 = iImplInfoArray[kk]->ImplementationUid();
OstTrace1( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL_DUP5, "New FDC Proxy implementation UID: 0x%08x", fdcUid2.iUid );
TInt fdcVersion2 = iImplInfoArray[kk]->Version();
OstTrace1( TRACE_NORMAL, CFDF_HANDLEECOMEVENTRECEIVEDL_DUP6, "FDC Proxy version UID: %d", fdcVersion2 );
}
// 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);
}
}
OstTraceFunctionExit0( CFDF_HANDLEECOMEVENTRECEIVEDL_EXIT );
}
// A bus event has occurred.
void CFdf::MbeoBusEvent()
{
OstTraceFunctionEntry0( CFDF_MBEOBUSEVENT_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_MBEOBUSEVENT, "iBusEvent.iEventType = %d", iBusEvent.iEventType );
OstTrace1( TRACE_NORMAL, CFDF_MBEOBUSEVENT_DUP1, "iBusEvent.iError = %d", iBusEvent.iError );
OstTrace1( TRACE_NORMAL, CFDF_MBEOBUSEVENT_DUP2, "iBusEvent.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.
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_MBEOBUSEVENT_DUP3, "Empty iEventQueue" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
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'.
if(!(iBusEvent.iError == KErrNone))
{
OstTrace0( TRACE_NORMAL, CFDF_MBEOBUSEVENT_DUP4, "iBusEvent error" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
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();
OstTraceFunctionExit0( CFDF_MBEOBUSEVENT_EXIT );
}
// 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)
{
OstTraceFunctionEntry0( CFDF_HANDLEDEVICEATTACHMENT_ENTRY );
// This is filled in by HandleDeviceAttachmentL on success.
CDeviceProxy* device;
TRAPD(err, HandleDeviceAttachmentL(aDeviceId, device));
if ( err )
{
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENT, "err = %d", err );
// There was an attachment failure, so we just increment the count of
// attachment failures.
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENT_DUP1, "Empty iEventQueue" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
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.
if(!device)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENT_DUP2, "Empty device" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
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();
OstTraceFunctionExit0( CFDF_HANDLEDEVICEATTACHMENT_EXIT );
}
// This does the 'device attachment' phase of the new device attachment only.
void CFdf::HandleDeviceAttachmentL(TUint aDeviceId, CDeviceProxy*& aDevice)
{
OstTraceFunctionEntry0( CFDF_HANDLEDEVICEATTACHMENTL_ENTRY );
// Create the device proxy
aDevice = CDeviceProxy::NewL(iHubDriver, aDeviceId);
CleanupStack::PushL(aDevice);
iCurrentDevice = aDevice;
// Get necessary descriptors (for this phase)
TInt err=aDevice->GetDeviceDescriptor(iDD);
if (err<0)
{
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENTL, "GetDeviceDescriptor error=%d", err );
User::Leave(err);
}
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP1, "iDD.USBBcd = 0x%04x", iDD.USBBcd() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP2, "iDD.DeviceClass = 0x%02x", iDD.DeviceClass() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP3, "iDD.DeviceSubClass = 0x%02x", iDD.DeviceSubClass() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP4, "iDD.DeviceProtocol = 0x%02x", iDD.DeviceProtocol() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP5, "iDD.MaxPacketSize0 = %d", iDD.MaxPacketSize0() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP6, "iDD.VendorId = 0x%04x", iDD.VendorId() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP7, "iDD.ProductId = 0x%04x", iDD.ProductId() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP8, "iDD.DeviceBcd = 0x%04x", iDD.DeviceBcd() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP9, "iDD.ManufacturerIndex = %d", iDD.ManufacturerIndex() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP10, "iDD.ProductIndex = %d", iDD.ProductIndex() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP11, "iDD.SerialNumberIndex = %d", iDD.SerialNumberIndex() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP12, "iDD.NumConfigurations = %d", iDD.NumConfigurations() );
err=aDevice->GetConfigurationDescriptor(iCD);
if(err<0)
{
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP13, "GetConfigurationDescriptor error=%d", err);
User::Leave(err);
}
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP14, "iCD.TotalLength = %d", iCD.TotalLength() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP15, "iCD.NumInterfaces = %d", iCD.NumInterfaces() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP16, "iCD.ConfigurationValue = %d", iCD.ConfigurationValue() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP17, "iCD.ConfigurationIndex = %d", iCD.ConfigurationIndex() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP18, "iCD.Attributes = %d", iCD.Attributes() );
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP19, "iCD.MaxPower = %d", iCD.MaxPower() );
const TUint8 numberOfInterfaces = iCD.NumInterfaces();
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP20, "numberOfInterfaces (field in config descriptor) = %d)", numberOfInterfaces );
if ( numberOfInterfaces == 0 )
{
OstTrace0( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP21, "Error: Usb Configuration Has No Interfaces");
User::Leave(KErrUsbConfigurationHasNoInterfaces);
}
// Walk the configuration bundle. Collect information on each interface
// (its number, class, subclass and protocol). This populates iInterfaces.
if(!(iInterfaces.Count() == 0))
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP22, "Error: Usb Configuration Has No Interfaces");
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if(!iCurrentDevice)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP23, "Empty iCurrentDevice");
User::Panic(KPanicCategory,__LINE__);
}
ParseL(iCD);
// Log iInterfaces.
const TUint interfaceCount = iInterfaces.Count();
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP24, "interfaceCount (parsed from bundle) = %d", interfaceCount );
#ifdef _DEBUG
OstTrace0( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP25, "Logging iInterfaces:");
for ( TUint ii = 0 ; ii < interfaceCount ; ++ii )
{
const TInterfaceInfo* ifInfo = iInterfaces[ii];
if(!ifInfo)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP26, "Empty ifInfo");
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
OstTraceExt5(TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP27, "\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 )
{
OstTrace0( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP28, "KErrUsbInterfaceCountMismatch");
User::Leave(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];
if(!lhs)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP29, "Empty lhs");
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
for ( TUint jj = ii+1 ; jj < interfaceCount ; ++jj )
{
const TInterfaceInfo* rhs = iInterfaces[jj];
if(!rhs)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP30, "Empty rhs");
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if ( lhs->iNumber == rhs->iNumber )
{
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP31, "KErrUsbDuplicateInterfaceNumbers; iNumber=%d", lhs->iNumber);
User::Leave(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,OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP32, "Load Logical Device error; error=%d", 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();
if(!attachmentEvent)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP33, "Empty attachmentEvent");
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
attachmentEvent->iInfo.iVid = iDD.VendorId();
attachmentEvent->iInfo.iPid = iDD.ProductId();
attachmentEvent->iInfo.iError = KErrNone;
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEATTACHMENTL_DUP34, "Empty iEventQueue");
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
iEventQueue->AddDeviceEvent(*attachmentEvent);
OstTrace1( TRACE_DUMP, CFDF_HANDLEDEVICEATTACHMENTL_DUP35, "***USB HOST STACK: SUCCESSFUL ATTACHMENT OF DEVICE (id %d)", aDeviceId );
OstTraceFunctionExit0( CFDF_HANDLEDEVICEATTACHMENTL_EXIT );
}
void CFdf::DoDriverLoading(CDeviceProxy& aDevice)
{
OstTraceFunctionEntry0( CFDF_DODRIVERLOADING_ENTRY );
// 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();
if(!driverLoadingEvent)
{
OstTrace0( TRACE_FATAL, CFDF_DODRIVERLOADING, "Empty driverLoadingEvent" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
// 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();
}
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_DODRIVERLOADING_DUP1, "Empty iEventQueue" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
iEventQueue->AddDeviceEvent(*driverLoadingEvent);
OstTraceFunctionExit0( CFDF_DODRIVERLOADING_EXIT );
}
void CFdf::DoDriverLoadingL(CDeviceProxy& aDevice)
{
OstTraceFunctionEntry0( CFDF_DODRIVERLOADINGL_ENTRY );
// Check whether driver loading is enabled.
if ( !iDriverLoadingEnabled )
{
// Complete driver load failure scenario.
aDevice.SetDriverLoadingEventData(EDriverLoadFailure, KErrUsbDriverLoadingDisabled);
OstTrace1( TRACE_NORMAL, CFDF_DODRIVERLOADINGL, "Leave with error %d", KErrGeneral );
User::Leave(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);
OstTrace0( TRACE_NORMAL, CFDF_DODRIVERLOADINGL_DUP1, "Leave with function Driver not Found" );
User::Leave(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();
OstTrace1( TRACE_DUMP, CFDF_DODRIVERLOADINGL_DUP2, "unclaimedInterfaces = %d", unclaimedInterfaces );
OstTrace1( TRACE_DUMP, CFDF_DODRIVERLOADINGL_DUP3, "anySuccess = %d", anySuccess );
OstTrace1( TRACE_DUMP, CFDF_DODRIVERLOADINGL_DUP4, "collectedErr = %d", collectedErr );
if(!(unclaimedInterfaces <= interfaceCount))
{
OstTrace0( TRACE_FATAL, CFDF_DODRIVERLOADINGL_DUP5, "interface Count error" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if(iDeviceDetachedTooEarly)
{
OstTrace0( TRACE_NORMAL, CFDF_DODRIVERLOADINGL_DUP6, "Device 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
OstTraceFunctionExit0( CFDF_DODRIVERLOADINGL_EXIT );
}
// Recursive function, originally called with the configuration descriptor.
// Builds up information on the interface descriptors in the configuration
// bundle.
void CFdf::ParseL(TUsbGenericDescriptor& aDesc)
{
OstTraceFunctionEntry0( CFDF_PARSEL_ENTRY );
OstTrace1( TRACE_DUMP, CFDF_PARSEL, "&aDesc = 0x%08x", &aDesc );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP1, "aDesc.ibDescriptorType = %d", aDesc.ibDescriptorType );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP2, "aDesc.iFirstChild = 0x%08x", aDesc.iFirstChild );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP3, "aDesc.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
{
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP4, "ifDesc.InterfaceNumber = %d", ifDesc.InterfaceNumber() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP5, "ifDesc.NumEndpoints = %d", ifDesc.NumEndpoints() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP6, "ifDesc.InterfaceClass = 0x%02x", ifDesc.InterfaceClass() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP7, "ifDesc.InterfaceSubClass = 0x%02x", ifDesc.InterfaceSubClass() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP8, "ifDesc.InterfaceProtocol = 0x%02x", ifDesc.InterfaceProtocol() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP9, "ifDesc.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);
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP10, "otgDesc.Attributes = %d", otgDesc.Attributes() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP11, "otgDesc.HNPSupported = %d", otgDesc.HNPSupported() );
OstTrace1( TRACE_DUMP, CFDF_PARSEL_DUP12, "otgDesc.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);
}
OstTraceFunctionExit0( CFDF_PARSEL_EXIT );
}
// 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)
{
OstTraceFunctionEntry0( CFDF_FINDDRIVERSFORINTERFACESUSINGSPECIFICKEYL_ENTRY );
const TUint interfaceCount = iInterfaces.Count();
for ( TUint ii = 0 ; ii < interfaceCount ; ++ii )
{
TInterfaceInfo* ifInfo = iInterfaces[ii];
if(!ifInfo)
{
OstTrace0( TRACE_FATAL, CFDF_FINDDRIVERSFORINTERFACESUSINGSPECIFICKEYL, "Empty ifInfo" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
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);
OstTraceExt1( TRACE_NORMAL, CFDF_FINDDRIVERSFORINTERFACESUSINGSPECIFICKEYL_DUP1, "searchKey = \"%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);
}
OstTraceFunctionExit0( CFDF_FINDDRIVERSFORINTERFACESUSINGSPECIFICKEYL_EXIT );
}
// 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)
{
OstTraceFunctionEntry0( CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_ENTRY );
OstTraceExt1( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY, "aSearchKey = \"%S\"", aSearchKey );
// Find an FDC matching this search key.
TSglQueIter<CFdcProxy> iter(iFunctionDrivers);
iter.SetToFirst();
CFdcProxy* fdc;
while ( ( fdc = iter++ ) != NULL )
{
OstTraceExt1( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP1, "FDC'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();
}
OstTrace1( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP2, "found matching FDC (0x%08x)", fdc );
const TUint count = aInterfacesGivenToFdc.Count();
OstTrace1( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP3, "logging aInterfacesGivenToFdc (interfaces being offered to the FDC): count = %d", count );
for ( TUint ii = 0 ; ii < count ; ++ii )
{
OstTraceExt2( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP4,
"index %u: interface number %u",
ii, aInterfacesGivenToFdc[ii] );
}
TInt err = fdc->NewFunction(aDevice.DeviceId(), aInterfacesGivenToFdc, iDD, iCD);
OstTrace1( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP5, "NewFunction 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 )
{
OstTraceExt2(TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP6,
"***USB HOST STACK: THE FOLLOWING INTERFACES OF DEVICE %u WERE SUCCESSFULLY PASSED TO FUNCTION DRIVER WITH IMPL UID 0x%08x",
(TInt32) aDevice.DeviceId(), fdc->ImplUid().iUid);
// 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];
if(!ifInfo)
{
OstTrace0( TRACE_FATAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP7, "Empty ifInfo" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if ( ifNum == ifInfo->iNumber
&& ifInfo->iClaimed
)
{
OstTrace1( TRACE_NORMAL, CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_DUP8, "***USB HOST STACK: bInterfaceNumber %d", ifNum );
}
}
}
aAnySuccess = ETrue;
}
else
{
aCollectedErr = err;
}
// We found a matching FDC for this interface- no need to look for more.
break;
}
}
OstTraceFunctionExit0( CFDF_FINDDRIVERFORINTERFACEUSINGSPECIFICKEY_EXIT );
}
void CFdf::HandleDeviceDetachment(TUint aDeviceId)
{
OstTraceFunctionEntry0( CFDF_HANDLEDEVICEDETACHMENT_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEDETACHMENT, "aDeviceId = %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
OstTrace0( TRACE_NORMAL, CFDF_HANDLEDEVICEDETACHMENT_DUP1, "found 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();
if(!detachmentEvent)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEDETACHMENT_DUP2, "Empty detachmentEvent" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVICEDETACHMENT_DUP3, "Empty iEventQueue" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
iEventQueue->AddDeviceEvent(*detachmentEvent);
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEDETACHMENT_DUP4, "***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);
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVICEDETACHMENT_DUP5, "FreeLogicalDevice( usbdi ) returned %d", err );
}
#endif // __OVER_DUMMYUSBDI__
break;
}
}
#ifdef _DEBUG
if ( !found )
{
OstTrace0( TRACE_NORMAL, CFDF_HANDLEDEVICEDETACHMENT_DUP6, "no matching device proxy found" );
}
#endif
OstTraceFunctionExit0( CFDF_HANDLEDEVICEDETACHMENT_EXIT );
}
void CFdf::HandleDevmonEvent(TInt aEvent)
{
OstTraceFunctionEntry0( CFDF_HANDLEDEVMONEVENT_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_HANDLEDEVMONEVENT, "aEvent = %d", aEvent );
if(!iEventQueue)
{
OstTrace0( TRACE_FATAL, CFDF_HANDLEDEVMONEVENT_DUP1, "Empty iEventQueue" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
iEventQueue->AddDevmonEvent(aEvent);
OstTraceFunctionExit0( CFDF_HANDLEDEVMONEVENT_EXIT );
}
void CFdf::TellFdcsOfDeviceDetachment(TUint aDeviceId)
{
OstTraceFunctionEntry0( CFDF_TELLFDCSOFDEVICEDETACHMENT_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_TELLFDCSOFDEVICEDETACHMENT, "aDeviceId = %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;
}
}
OstTraceFunctionExit0( CFDF_TELLFDCSOFDEVICEDETACHMENT_EXIT );
}
TUint32 CFdf::TokenForInterface(TUint8 aInterface)
{
OstTraceFunctionEntry0( CFDF_TOKENFORINTERFACE_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_TOKENFORINTERFACE, "aInterface = %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];
if(!ifInfo)
{
OstTrace0( TRACE_FATAL, CFDF_TOKENFORINTERFACE_DUP1, "Empty ifInfo" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if ( ifInfo->iNumber == aInterface )
{
found = ETrue;
// The FDC tried to claim an interface that was already claimed.
if(ifInfo->iClaimed)
{
OstTrace0( TRACE_FATAL, CFDF_TOKENFORINTERFACE_DUP2, "iClaimed error" );
User::Panic(KPanicCategory,__LINE__);
}
ifInfo->iClaimed = ETrue;
break;
}
}
// Could not find interface in the interface array- the FDC tried to claim
// an interface it had not been offered.
if(!found)
{
OstTrace0( TRACE_FATAL, CFDF_TOKENFORINTERFACE_DUP3, "not found" );
User::Panic(KPanicCategory,__LINE__);
}
if(!iCurrentDevice)
{
OstTrace0( TRACE_FATAL, CFDF_TOKENFORINTERFACE_DUP4, "Empty iCurrentDevice" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
// 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:
OstTraceExt2( TRACE_FATAL, CFDF_TOKENFORINTERFACE_DUP5, "Unexpected error %d when requesting token for aInterface %d",err,aInterface);
User::Panic(KPanicCategory,__LINE__);
break;
}
OstTraceExt2( TRACE_NORMAL, CFDF_TOKENFORINTERFACE_DUP6,
"Token for interface %hhu is = %u",aInterface, token);
OstTraceFunctionExit0( CFDF_TOKENFORINTERFACE_EXIT );
return token;
}
CDeviceProxy* CFdf::DeviceProxyL(TUint aDeviceId) const
{
OstTraceFunctionEntry0( CFDF_DEVICEPROXYL_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_DEVICEPROXYL, "aDeviceId = %d", aDeviceId );
TSglQueIter<CDeviceProxy> iter(const_cast<CFdf*>(this)->iDevices);
iter.SetToFirst();
CDeviceProxy* device = NULL;
while ( ( device = iter++ ) != NULL )
{
if ( device->DeviceId() == aDeviceId )
{
OstTrace1( TRACE_NORMAL, CFDF_DEVICEPROXYL_DUP1, "device = 0x%08x", device );
OstTraceFunctionExit0( CFDF_DEVICEPROXYL_EXIT );
return device;
}
}
OstTrace0( TRACE_NORMAL, CFDF_DEVICEPROXYL_DUP2, "KErrNotFound");
User::Leave(KErrNotFound);
OstTraceFunctionExit0( CFDF_DEVICEPROXYL_EXIT_DUP1 );
return NULL; // avoid warning
}
const RArray<TUint>& CFdf::GetSupportedLanguagesL(TUint aDeviceId) const
{
OstTraceFunctionEntry0( CFDF_GETSUPPORTEDLANGUAGESL_ENTRY );
OstTrace1( TRACE_NORMAL, CFDF_GETSUPPORTEDLANGUAGESL, "aDeviceId = %d", aDeviceId );
CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId);
return deviceProxy->GetSupportedLanguages();
}
void CFdf::GetManufacturerStringDescriptorL(TUint aDeviceId, TUint32 aLangId, TName& aString) const
{
OstTraceFunctionEntry0( CFDF_GETMANUFACTURERSTRINGDESCRIPTORL_ENTRY );
OstTraceExt2( TRACE_NORMAL, CFDF_GETMANUFACTURERSTRINGDESCRIPTORL,
"aDeviceId = %u, aLangId = 0x%08x", (TUint32)aDeviceId, aLangId );
CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId);
deviceProxy->GetManufacturerStringDescriptorL(aLangId, aString);
OstTraceExt1( TRACE_NORMAL, CFDF_GETMANUFACTURERSTRINGDESCRIPTORL_DUP1, "aString = \"%S\"", aString );
OstTraceFunctionExit0( CFDF_GETMANUFACTURERSTRINGDESCRIPTORL_EXIT );
}
void CFdf::GetProductStringDescriptorL(TUint aDeviceId, TUint32 aLangId, TName& aString) const
{
OstTraceFunctionEntry0( CFDF_GETPRODUCTSTRINGDESCRIPTORL_ENTRY );
OstTraceExt2( TRACE_NORMAL, CFDF_GETPRODUCTSTRINGDESCRIPTORL,
"aDeviceId = %u, aLangId = 0x%04x", (TUint32)aDeviceId, aLangId );
CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId);
deviceProxy->GetProductStringDescriptorL(aLangId, aString);
OstTraceExt1( TRACE_NORMAL, CFDF_GETPRODUCTSTRINGDESCRIPTORL_DUP1, "aString = \"%S\"", aString );
OstTraceFunctionExit0( CFDF_GETPRODUCTSTRINGDESCRIPTORL_EXIT );
}
void CFdf::GetOtgDeviceDescriptorL(TInt aDeviceId, TOtgDescriptor& aDescriptor) const
{
OstTraceFunctionEntry0( CFDF_GETOTGDEVICEDESCRIPTORL_ENTRY );
DeviceProxyL(aDeviceId)->GetOtgDescriptorL(aDescriptor);
OstTraceFunctionExit0( CFDF_GETOTGDEVICEDESCRIPTORL_EXIT );
}
void CFdf::GetSerialNumberStringDescriptorL(TUint aDeviceId, TUint32 aLangId, TName& aString) const
{
OstTraceFunctionEntry0( CFDF_GETSERIALNUMBERSTRINGDESCRIPTORL_ENTRY );
OstTraceExt2( TRACE_NORMAL, CFDF_GETSERIALNUMBERSTRINGDESCRIPTORL,
"aDeviceId = %u, aLangId = 0x%08x", (TUint32)aDeviceId, aLangId );
CDeviceProxy* deviceProxy = DeviceProxyL(aDeviceId);
deviceProxy->GetSerialNumberStringDescriptorL(aLangId, aString);
OstTraceExt1( TRACE_NORMAL, CFDF_GETSERIALNUMBERSTRINGDESCRIPTORL_DUP1, "aString = \"%S\"", aString );
OstTraceFunctionExit0( CFDF_GETSERIALNUMBERSTRINGDESCRIPTORL_EXIT );
}
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);
OstTrace1( TRACE_NORMAL, CFDF_APPENDINTERFACENUMBERTOARRAYL, "Leave with error: %d", err );
User::Leave(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;
OstTraceExt1( TRACE_NORMAL, CFDF_SEARCHFORADEVICEFUNCTIONDRIVERL, "FDC's default_data field = \"%S\"", fdc->DefaultDataField());
// 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();
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;
OstTrace1( TRACE_NORMAL, CFDF_SEARCHFORADEVICEFUNCTIONDRIVERL_DUP1, "found matching FDC (0x%08x)", fdc );
TInt err = fdc->NewFunction(aDevice.DeviceId(), interfaces, iDD, iCD);
OstTrace1( TRACE_NORMAL, CFDF_SEARCHFORADEVICEFUNCTIONDRIVERL_DUP2, "NewFunction 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)
{
OstTraceFunctionEntry0( CFDF_FORMATDEVICESEARCHKEY_ENTRY );
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:
{
OstTrace1( TRACE_FATAL, CFDF_FORMATDEVICESEARCHKEY, "Invalid aDeviceSearchKeys=%d", aDeviceSearchKeys );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
}
OstTraceExt1( TRACE_NORMAL, CFDF_FORMATDEVICESEARCHKEY_DUP1, "aSearchKey = \"%s\"", aSearchKey );
OstTraceFunctionExit0( CFDF_FORMATDEVICESEARCHKEY_EXIT );
}
//
// Format the string aSearchKey according to aSearchKeys to search for Interface Functions drivers
//
void CFdf::FormatInterfaceSearchKey(TDes8& aSearchKey, TInterfaceSearchKeys aSearchKeys, const TInterfaceInfo& aIfInfo)
{
OstTraceFunctionEntry0( CFDF_FORMATINTERFACESEARCHKEY_ENTRY );
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:
{
OstTrace1( TRACE_FATAL, CFDF_FORMATINTERFACESEARCHKEY, "Invalid aSearchKeys=%d", aSearchKeys );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
}
OstTraceExt1( TRACE_NORMAL, CFDF_FORMATINTERFACESEARCHKEY_DUP1, "aSearchKey = \"%s\"", aSearchKey );
OstTraceFunctionExit0( CFDF_FORMATINTERFACESEARCHKEY_EXIT );
}
TUint CFdf::UnclaimedInterfaceCount() const
{
OstTraceFunctionEntry0( CFDF_UNCLAIMEDINTERFACECOUNT_ENTRY );
TUint unclaimedInterfaces = 0;
for ( TUint ii = 0 ; ii < iInterfaces.Count() ; ++ii )
{
TInterfaceInfo* ifInfo = iInterfaces[ii];
if(!ifInfo)
{
OstTrace0( TRACE_FATAL, CFDF_UNCLAIMEDINTERFACECOUNT, "Empty ifInfo" );
__ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory,__LINE__));
}
if ( !ifInfo->iClaimed )
{
OstTrace1( TRACE_NORMAL, CFDF_UNCLAIMEDINTERFACECOUNT_DUP1, "unclaimed interface: ifInfo->iNumber = %d", ifInfo->iNumber );
++unclaimedInterfaces;
}
}
OstTrace1( TRACE_NORMAL, CFDF_UNCLAIMEDINTERFACECOUNT_DUP2, "unclaimedInterfaces = \"%d\"", unclaimedInterfaces );
OstTraceFunctionExit0( CFDF_UNCLAIMEDINTERFACECOUNT_EXIT );
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));
}
}
}