/*
* 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 <usb/usblogger.h>
#include <usbhostdefs.h>
#include "utils.h"
#include "event.h"
#include "deviceproxy.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "deviceproxyTraces.h"
#endif

#ifdef _DEBUG
#define LOG Log()
_LIT(KPanicCategory,"devproxy");
#else
#define LOG
#endif



CDeviceProxy* CDeviceProxy::NewL(RUsbHubDriver& aHubDriver, TUint aDeviceId)
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_NEWL_ENTRY );
    
	CDeviceProxy* self = new(ELeave) CDeviceProxy(aDeviceId);
	CleanupStack::PushL(self);
	self->ConstructL(aHubDriver);
	CLEANUPSTACK_POP1(self);
	OstTraceFunctionExit0( CDEVICEPROXY_NEWL_EXIT );
	return self;
	}

CDeviceProxy::CDeviceProxy(TUint aDeviceId)
:	iId(aDeviceId)
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_CDEVICEPROXY_CONS_ENTRY );    
	}

void CDeviceProxy::ConstructL(RUsbHubDriver& aHubDriver)
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_CONSTRUCTL_ENTRY );
    
    TInt err=iHandle.Open(aHubDriver, iId);
    if (err<0)
        {
        OstTrace1( TRACE_NORMAL, CDEVICEPROXY_CONSTRUCTL, "handle open with error %d", err );
        User::Leave(err);
        }

	// Pre-allocate objects relating to this device for the event queue.
	iAttachmentEvent = new(ELeave) TDeviceEvent;
	iAttachmentEvent->iInfo.iEventType = EDeviceAttachment;
	iAttachmentEvent->iInfo.iDeviceId = iId;

	iDriverLoadingEvent = new(ELeave) TDeviceEvent;
	iDriverLoadingEvent->iInfo.iEventType = EDriverLoad;
	iDriverLoadingEvent->iInfo.iDeviceId = iId;

	iDetachmentEvent = new(ELeave) TDeviceEvent;
	iDetachmentEvent->iInfo.iEventType = EDeviceDetachment;
	iDetachmentEvent->iInfo.iDeviceId = iId;
	
	ReadStringDescriptorsL();

	LOG;
	OstTraceFunctionExit0( CDEVICEPROXY_CONSTRUCTL_EXIT );
	}

void CDeviceProxy::ReadStringDescriptorsL()
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_READSTRINGDESCRIPTORSL_ENTRY );
    
	// wait 10 ms before reading any string descriptors
	// to avoid IOP issues with some USB devices (e.g. PNY Attache)
	User::After(10000);

	// First read string descriptor 0 (supported languages).
	// For each supported language, read the manufacturer, product and serial
	// number string descriptors (as supported). (These are not cached in
	// USBD.)
	// To look up these string descriptors we need to get the device
	// descriptor. The device descriptor *is* cached in USBD, so we don't
	// remember our own copy, even though it is queried later by the CFdf.

	// '0' is the index of the string descriptor which holds the supported
	// language IDs.
	TBuf8<256> stringBuf;
	TUsbStringDescriptor* stringDesc = NULL;
	
	if(!(iHandle.Handle()))
	    {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP1, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
	    }

	TInt err=iHandle.GetStringDescriptor(stringDesc, stringBuf, 0);
	LEAVEIFERRORL(err, OstTrace1( TRACE_ERROR, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP6, 
	"iHandle.GetStringDescriptor error %d", err ););
	CleanupStack::PushL(*stringDesc);

	// Copy the language IDs into our array.
	TUint index = 0;
	TInt16 langId = stringDesc->GetLangId(index);
	while ( langId != KErrNotFound )
		{
        OstTrace1( TRACE_NORMAL, CDEVICEPROXY_READSTRINGDESCRIPTORSL, "\tsupported language: 0x%04x", langId );
        
		iLangIds.AppendL(langId); // stored as TUint
		++index;
		langId = stringDesc->GetLangId(index);
		}

	CleanupStack::PopAndDestroy(stringDesc);

	// Get the actual strings for each supported language.
	TUsbDeviceDescriptor deviceDescriptor;
	if(!(iHandle.Handle()))
	    {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP2, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
	    }
	    
	err=iHandle.GetDeviceDescriptor(deviceDescriptor);
	LEAVEIFERRORL(err, OstTrace1( TRACE_ERROR, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP7, 
	"iHandle.GetDeviceDescriptor error %d", err ););
	
	TUint8 manufacturerStringDescriptorIndex = deviceDescriptor.ManufacturerIndex();
	TUint8 productStringDescriptorIndex = deviceDescriptor.ProductIndex();
	TUint8 serialNumberStringDescriptorIndex = deviceDescriptor.SerialNumberIndex();
	PopulateStringDescriptorsL(manufacturerStringDescriptorIndex, iManufacturerStrings);
	PopulateStringDescriptorsL(productStringDescriptorIndex, iProductStrings);
	PopulateStringDescriptorsL(serialNumberStringDescriptorIndex, iSerialNumberStrings);
	if(!(iManufacturerStrings.Count() == iLangIds.Count()))
	    {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP3, "iLangIds error" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
	    }
	if(!(iProductStrings.Count() == iLangIds.Count()))
	    {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP4, "iLangIds error" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
	    }
    if(!(iSerialNumberStrings.Count() == iLangIds.Count()))
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_READSTRINGDESCRIPTORSL_DUP5, "iLangIds error" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }
	OstTraceFunctionExit0( CDEVICEPROXY_READSTRINGDESCRIPTORSL_EXIT );
	}

// Populates the given array with the supported language variants of the given
// string. Can only leave with KErrNoMemory, which fails instantiation of the
// CDeviceProxy. (It is legal for instance for manufacturer strings to be
// supported but serial number strings to *not* be.)
void CDeviceProxy::PopulateStringDescriptorsL(TUint8 aStringDescriptorIndex, RArray<TName>& aStringArray)
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_POPULATESTRINGDESCRIPTORSL_ENTRY );
    
	const TUint langCount = iLangIds.Count();
	for ( TUint ii = 0 ; ii < langCount ; ++ii )
		{
		TName string;
		TRAPD(err, GetStringDescriptorFromUsbdL(iLangIds[ii], string, aStringDescriptorIndex));
		if ( err == KErrNotFound)
			{
			// Make sure the string is blanked before storing it.
			string = KNullDesC();
			}
		else
			{            
			LEAVEIFERRORL(err, OstTrace1( TRACE_NORMAL, CDEVICEPROXY_POPULATESTRINGDESCRIPTORSL, "err=%d", err ););
			}

		err=aStringArray.Append(string);
		LEAVEIFERRORL(err, OstTrace0( TRACE_NORMAL, CDEVICEPROXY_POPULATESTRINGDESCRIPTORSL_DUP1, "aStringArray append error"););
		}
	OstTraceFunctionExit0( CDEVICEPROXY_POPULATESTRINGDESCRIPTORSL_EXIT );
	}

CDeviceProxy::~CDeviceProxy()
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_CDEVICEPROXY_DES_ENTRY );
    
	LOG;

	// In the design, the event objects should all have had ownership taken
	// onto the event queue by now. The owner of the device proxy is required
	// to take ownership of these objects before destroying the proxy.
	// However, we might hit the destructor due to an out-of-memory failure
	// during construction, so we can't assert this, and we still have to
	// destroy the objects.
	delete iAttachmentEvent;
	delete iDriverLoadingEvent;
	delete iDetachmentEvent;
	delete iOtgDescriptor;

	iLangIds.Reset();
	iManufacturerStrings.Reset();
	iProductStrings.Reset();
	iSerialNumberStrings.Reset();

	iHandle.Close();
	OstTraceFunctionExit0( CDEVICEPROXY_CDEVICEPROXY_DES_EXIT );
	}

TInt CDeviceProxy::GetDeviceDescriptor(TUsbDeviceDescriptor& aDescriptor)
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_GETDEVICEDESCRIPTOR_ENTRY );
    if(!(iHandle.Handle()))
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETDEVICEDESCRIPTOR_DUP1, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }
	TInt err = iHandle.GetDeviceDescriptor(aDescriptor);

	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETDEVICEDESCRIPTOR, "\terr = %d", err );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETDEVICEDESCRIPTOR_EXIT );
	return err;
	}

TInt CDeviceProxy::GetConfigurationDescriptor(TUsbConfigurationDescriptor& aDescriptor) const
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_GETCONFIGURATIONDESCRIPTOR_ENTRY );
    if(!(iHandle.Handle()))
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETCONFIGURATIONDESCRIPTOR, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }
	TInt err = const_cast<RUsbDevice&>(iHandle).GetConfigurationDescriptor(aDescriptor);

	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETCONFIGURATIONDESCRIPTOR_DUP1, "\terr = %d", err );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETCONFIGURATIONDESCRIPTOR_EXIT );
	return err;
	}

TInt CDeviceProxy::GetTokenForInterface(TUint aIndex, TUint32& aToken) const
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETTOKENFORINTERFACE_ENTRY );
    if(!(iHandle.Handle()))
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETTOKENFORINTERFACE_DUP1, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }
    // We shouldn't need to worry about whether the device is suspended or
	// resumed before doing this. This function is only called if we find FDs
	// for the device, in which case we wouldn't have suspended it in the
	// first place.
	TInt err = const_cast<RUsbDevice&>(iHandle).GetTokenForInterface(aIndex, aToken);

	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETTOKENFORINTERFACE, "\terr = %d", err );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETTOKENFORINTERFACE_EXIT );
	return err;
	}

const RArray<TUint>& CDeviceProxy::GetSupportedLanguages() const
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_GETSUPPORTEDLANGUAGES_ENTRY );
    
	return iLangIds;
	}

void CDeviceProxy::GetManufacturerStringDescriptorL(TUint32 aLangId, TName& aString) const
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETMANUFACTURERSTRINGDESCRIPTORL_ENTRY );
	
	GetStringDescriptorFromCacheL(aLangId, aString, iManufacturerStrings);
	OstTraceFunctionExit0( CDEVICEPROXY_GETMANUFACTURERSTRINGDESCRIPTORL_EXIT );
	}

void CDeviceProxy::GetProductStringDescriptorL(TUint32 aLangId, TName& aString) const
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_GETPRODUCTSTRINGDESCRIPTORL_ENTRY );
    
	GetStringDescriptorFromCacheL(aLangId, aString, iProductStrings);
	OstTraceFunctionExit0( CDEVICEPROXY_GETPRODUCTSTRINGDESCRIPTORL_EXIT );
	}

void CDeviceProxy::GetSerialNumberStringDescriptorL(TUint32 aLangId, TName& aString) const
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETSERIALNUMBERSTRINGDESCRIPTORL_ENTRY );
	
	GetStringDescriptorFromCacheL(aLangId, aString, iSerialNumberStrings);
	OstTraceFunctionExit0( CDEVICEPROXY_GETSERIALNUMBERSTRINGDESCRIPTORL_EXIT );
	}

void CDeviceProxy::GetOtgDescriptorL(TOtgDescriptor& aDescriptor) const
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETOTGDESCRIPTORL_ENTRY );
	
	if (iOtgDescriptor)
		{
		aDescriptor = *iOtgDescriptor;
		}
	else
		{
        OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETOTGDESCRIPTORL, "Error=%d", KErrNotSupported );
        User::Leave(KErrNotSupported);
		}
	OstTraceFunctionExit0( CDEVICEPROXY_GETOTGDESCRIPTORL_EXIT );
	}

void CDeviceProxy::SetOtgDescriptorL(const TUsbOTGDescriptor& aDescriptor)
	{
	if (iOtgDescriptor)
		{
		delete iOtgDescriptor;
		iOtgDescriptor = NULL;
		}
	iOtgDescriptor = new (ELeave) TOtgDescriptor();

	iOtgDescriptor->iDeviceId = iId;
	iOtgDescriptor->iAttributes = aDescriptor.Attributes();
	
	OstTrace0( TRACE_NORMAL, CDEVICEPROXY_SETOTGDESCRIPTORL0, "\t>SetOtgDescriptorL");
	iOtgDescriptor->iBcdOTG = aDescriptor.BcdOTG();
	OstTrace0( TRACE_NORMAL, CDEVICEPROXY_SETOTGDESCRIPTORL1, "\t<SetOtgDescriptorL");
	}

// Used during instantiation to read supported strings.
void CDeviceProxy::GetStringDescriptorFromUsbdL(TUint32 aLangId, TName& aString, TUint8 aStringDescriptorIndex) const
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL_ENTRY );
	
	OstTraceExt2( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL, "\taLangId = 0x%d, aStringDescriptorIndex = %d", aLangId, aStringDescriptorIndex );
	
	// If the string is not defined by the device, leave.
	if ( aStringDescriptorIndex == 0 )
		{
        OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL_DUP1, "err=%d", KErrNotFound );
 		User::Leave(KErrNotFound);
		}

	TBuf8<255> stringBuf;
	TUsbStringDescriptor* stringDesc = NULL;
	if(!(iHandle.Handle()))
	    {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL_DUP2, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
	    }
	TInt err=const_cast<RUsbDevice&>(iHandle).GetStringDescriptor(stringDesc, stringBuf, aStringDescriptorIndex, aLangId);
	if(err<0)
	    {
        OstTrace0( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL_DUP4, "GetStringDescriptor error" );
        User::Leave(err);
	    }
	stringDesc->StringData(aString);
	stringDesc->DestroyTree();
	delete stringDesc;
	OstTraceExt1( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL_DUP3, "\taString = \"%S\"", aString );
	OstTraceFunctionExit0( CDEVICEPROXY_GETSTRINGDESCRIPTORFROMUSBDL_EXIT );
	}

// Called indirectly by users of this class to query a string descriptor.
void CDeviceProxy::GetStringDescriptorFromCacheL(TUint32 aLangId, TName& aString, const RArray<TName>& aStringArray) const
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_GETSTRINGDESCRIPTORFROMCACHEL_ENTRY );
    
    OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMCACHEL_DUP1, "\taLangId = 0x%04x", aLangId );
    
	// If the lang ID is not supported by the device, leave. At the same time
	// find the index of the required string in the given string array.
	const TUint langCount = iLangIds.Count();
	TUint index = 0;
	for ( index = 0 ; index < langCount ; ++index )
		{
		if ( iLangIds[index] == aLangId )
			{
			break;
			}
		}
	if ( index == langCount )
		{
  		OstTrace0( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMCACHEL, "CDeviceProxy::GetStringDescriptorFromCacheL" );
		User::Leave(KErrNotFound);
		}

	aString = aStringArray[index];
	OstTraceExt1( TRACE_NORMAL, CDEVICEPROXY_GETSTRINGDESCRIPTORFROMCACHEL_DUP2, "\taString = \"%S\"", aString );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETSTRINGDESCRIPTORFROMCACHEL_EXIT );
	}

TInt CDeviceProxy::Suspend()
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_SUSPEND_ENTRY );
	if(!(iHandle.Handle()))
	    {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_SUSPEND_DUP1, "Empty handler" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
	    }
	TInt ret = iHandle.Suspend();

	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_SUSPEND, "\tret = %d", ret );
	
	OstTraceFunctionExit0( CDEVICEPROXY_SUSPEND_EXIT );
	return ret;
	}

TUint CDeviceProxy::DeviceId() const
	{
	return iId;
	}

void CDeviceProxy::SetDriverLoadingEventData(TDriverLoadStatus aStatus, TInt aError)
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_SETDRIVERLOADINGEVENTDATA_ENTRY );
	
    OstTraceExt2( TRACE_NORMAL, CDEVICEPROXY_SETDRIVERLOADINGEVENTDATA, "\taStatus = %d, aError = %d", aStatus, aError );
    if(!iDriverLoadingEvent)
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_SETDRIVERLOADINGEVENTDATA_DUP1, "Empty Driver Loading Event" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }
 	iDriverLoadingEvent->iInfo.iDriverLoadStatus = aStatus;
	iDriverLoadingEvent->iInfo.iError = aError;

	LOG;
	OstTraceFunctionExit0( CDEVICEPROXY_SETDRIVERLOADINGEVENTDATA_EXIT );
	}

TDeviceEvent* CDeviceProxy::GetAttachmentEventObject()
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETATTACHMENTEVENTOBJECT_ENTRY );
	
    LOG;
    if(!iAttachmentEvent)
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETATTACHMENTEVENTOBJECT_DUP1, "Empty Attechment Event" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }

	TDeviceEvent* const obj = iAttachmentEvent;
	iAttachmentEvent = NULL;
	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETATTACHMENTEVENTOBJECT, "\tobj = 0x%08x", obj );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETATTACHMENTEVENTOBJECT_EXIT );
	return obj;
	}

TDeviceEvent* CDeviceProxy::GetDriverLoadingEventObject()
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETDRIVERLOADINGEVENTOBJECT_ENTRY );
	
    LOG;
    if(!iDriverLoadingEvent)
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETDRIVERLOADINGEVENTOBJECT, "Empty Driver Loading Event" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }

	TDeviceEvent* const obj = iDriverLoadingEvent;
	iDriverLoadingEvent = NULL;
	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETDRIVERLOADINGEVENTOBJECT_DUP1, "\tobj = 0x%08x", obj );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETDRIVERLOADINGEVENTOBJECT_EXIT );
	return obj;
	}

TDeviceEvent* CDeviceProxy::GetDetachmentEventObject()
	{
	OstTraceFunctionEntry0( CDEVICEPROXY_GETDETACHMENTEVENTOBJECT_ENTRY );
    LOG;

    if(!iDetachmentEvent)
        {
        OstTrace0( TRACE_FATAL, CDEVICEPROXY_GETDETACHMENTEVENTOBJECT, "Empty Detachment Event" );
        __ASSERT_DEBUG(EFalse,User::Panic(KPanicCategory, __LINE__));
        }
	TDeviceEvent* const obj = iDetachmentEvent;
	iDetachmentEvent = NULL;
	
	OstTrace1( TRACE_NORMAL, CDEVICEPROXY_GETDETACHMENTEVENTOBJECT_DUP1, "\tobj = 0x%08x", obj );
	
	OstTraceFunctionExit0( CDEVICEPROXY_GETDETACHMENTEVENTOBJECT_EXIT );
	return obj;
	}


void CDeviceProxy::Log()
	{
    OstTraceFunctionEntry0( CDEVICEPROXY_LOG_ENTRY );
    
    OstTrace1( TRACE_DUMP, CDEVICEPROXY_LOG, "\tiId = %d", iId );
    OstTrace1( TRACE_DUMP, CDEVICEPROXY_LOG_DUP1, "\tiHandle.Handle() = %d", iHandle.Handle() );
    
    if ( iAttachmentEvent )
		{
        OstTrace0( TRACE_DUMP, CDEVICEPROXY_LOG_DUP2, "\tlogging iAttachmentEvent" );
 		iAttachmentEvent->Log();
		}
	if ( iDriverLoadingEvent )
		{
        OstTrace0( TRACE_DUMP, CDEVICEPROXY_LOG_DUP3, "\tlogging iDriverLoadingEvent" );

		iDriverLoadingEvent->Log();
		}
	if ( iDetachmentEvent )
		{
        OstTrace0( TRACE_DUMP, CDEVICEPROXY_LOG_DUP4, "\tlogging iDetachmentEvent" );
		iDetachmentEvent->Log();
		}
	const TUint langCount = iLangIds.Count();
	const TUint manufacturerCount = iManufacturerStrings.Count();
	const TUint productCount = iProductStrings.Count();
	const TUint serialNumberCount = iSerialNumberStrings.Count();

	// from the code below we can see that some protection have been added
	// if(ii<manufacturerCount) etc...
	// This has been done to protect in case there have been an incomplete construction etc..
	// when logging the data

	OstTrace1( TRACE_DUMP, CDEVICEPROXY_LOG_DUP5, "C\tlangCount = %d", langCount );
	
	for ( TUint ii = 0 ; ii < langCount ; ++ii )
		{
        OstTrace1( TRACE_FLOW, CDEVICEPROXY_LOG_DUP6, "\tlang ID 0x%04x:", iLangIds[ii] );
        
		if(ii<manufacturerCount)
			{
            OstTraceExt1( TRACE_FLOW, CDEVICEPROXY_LOG_DUP7, "\t\tmanufacturer string: \"%S\"", iManufacturerStrings[ii] );
            }
		if(ii<productCount)
			{
            OstTraceExt1( TRACE_FLOW, CDEVICEPROXY_LOG_DUP8, "\t\tproduct string: \"%S\"", iProductStrings[ii]);
		 	}
		if(ii<serialNumberCount)
			{
            OstTraceExt1( TRACE_FLOW, CDEVICEPROXY_LOG_DUP9, "\t\tserial number string: \"%S\"", iSerialNumberStrings[ii]);
			}

		}
	OstTraceFunctionExit0( CDEVICEPROXY_LOG_EXIT );
	}

