/*
* 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
*/

#ifndef DEVICEPROXY_H
#define DEVICEPROXY_H

#include <e32base.h>
#include "usbhoststack.h"

#ifdef __OVER_DUMMYUSBDI__
#include <usbhost/dummyusbdi/d32usbdi_hubdriver.h>
#else
#include <d32usbdi_hubdriver.h>
#endif

class TDeviceEvent;
class TOtgDescriptor;

NONSHARABLE_CLASS(CDeviceProxy) : public CBase
	{
public:
	/** Link between elements of this type in a TSglQue. */
	TSglQueLink iLink;

public:
	static CDeviceProxy* NewL(RUsbHubDriver& aHubDriver, TUint aDeviceId);
	~CDeviceProxy();

public: // querying information from the device
	TInt GetDeviceDescriptor(TUsbDeviceDescriptor& aDescriptor);
	TInt GetConfigurationDescriptor(TUsbConfigurationDescriptor& aDescriptor) const;
	const RArray<TUint>& GetSupportedLanguages() const;
	void GetManufacturerStringDescriptorL(TUint32 aLangId, TName& aString) const;
	void GetProductStringDescriptorL(TUint32 aLangId, TName& aString) const;
	void GetSerialNumberStringDescriptorL(TUint32 aLangId, TName& aString) const;
	
	void GetOtgDescriptorL(TOtgDescriptor& aDescriptor) const;
	void SetOtgDescriptorL(const TUsbOTGDescriptor& aDescriptor);

public: // management
	TInt GetTokenForInterface(TUint aIndex, TUint32& aToken) const;
	TUint DeviceId() const;
	void SetDriverLoadingEventData(TDriverLoadStatus aStatus, TInt aError = KErrNone);
	TInt Suspend();

	// These methods TAKE OWNERSHIP of the relevant objects.
	TDeviceEvent* GetAttachmentEventObject();
	TDeviceEvent* GetDriverLoadingEventObject();
	TDeviceEvent* GetDetachmentEventObject();
	inline void SetMultipleDriversFlag()
	{
		iMultipleDriversFound = ETrue;
	}

	inline TBool MultipleDriversFlag()
	{
		return iMultipleDriversFound;
	}
	inline void SetHasIADFlag()
	{
		iHasIAD = ETrue;
	}
	inline TBool HasIADFlag()
	{
		return iHasIAD;
	}

private:
	CDeviceProxy(TUint aDeviceId);
	void ConstructL(RUsbHubDriver& aHubDriver);

private: // utility
	void Log();
	void ReadStringDescriptorsL();
	void PopulateStringDescriptorsL(TUint8 aStringDescriptorIndex, RArray<TName>& aStringArray);
	void GetStringDescriptorFromUsbdL(TUint32 aLangId, TName& aString, TUint8 aStringDescriptorIndex) const;
	void GetStringDescriptorFromCacheL(TUint32 aLangId, TName& aString, const RArray<TName>& aStringArray) const;

private: // owned
	RUsbDevice iHandle;
	const TUint iId;

	TDeviceEvent* iAttachmentEvent;
	TDeviceEvent* iDriverLoadingEvent;
	TDeviceEvent* iDetachmentEvent;

	// The design of string descriptor access in this class deserves some 
	// explanation.
	// In the simplest implementation of the FDF, we handle a device 
	// attachment without getting or storing any string descriptors from the 
	// device. If the FDF doesn't load any drivers for the device, it must 
	// suspend the device to save power. If USBMAN, subsequent to this, 
	// queries any string descriptors, the FDF will have to resume the device 
	// first (string descriptors are not requested or cached by USBD). 
	// Resuming a device is an asynchronous operation. We must therefore 
	// either make querying a string descriptor asynchronous as far as USBMAN 
	// is concerned (which would clearly make the relevant APIs much less 
	// friendly) or find another way round. [For completeness: this 
	// asynchronicity would rely on 
	// RHubDriver::QueueDeviceStateChangeNotification.]
	// Solution 1: if the FDF doesn't load drivers for the device, wait until 
	// USBSVR has queried string descriptors from us before suspending the 
	// device. Con: USBMAN only queries string descriptors when its client (in 
	// licensee-land) does so. We can't make any assumptions about their doing 
	// it in a timely manner or indeed at all. 
	// Solution 2: use User::After to give the device time to resume 
	// synchronously. Con: this is a major no-no in a production thread which 
	// must remain responsive to user requests and lower-level events. 
	// Mentioned only for completeness.
	// Solution 3 (implemented): request and cache all supported string 
	// descriptors at attachment time. String descriptors are typically small 
	// (a dozen characters, say), we only support 3 of them (manufacturer, 
	// product and serial number- not all of which may actually be supported 
	// by a particular device) and there is usually only 1 language, if that. 
	// Having cached the string descriptors, it is trivial to look them up 
	// later when the client wants.
	// These arrays are tied together, i.e. iManufacturerStrings[2] is the 
	// manufacturer string in the language with ID iLangIds[2]. Note that this 
	// may be KNullDesC if the device doesn't support the manufacturer string 
	// descriptor, but there's still an entry in the array for it.
	RArray<TUint> iLangIds;
	RArray<TName> iManufacturerStrings;
	RArray<TName> iProductStrings;
	RArray<TName> iSerialNumberStrings;
	TBool		  iHasIAD;
	TBool         iMultipleDriversFound;
	TOtgDescriptor* iOtgDescriptor; // Owned
	};

#endif // DEVICEPROXY_H
