kernel/eka/drivers/usbcc/descriptors.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 24 41f0cfe18c80
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// e32/drivers/usbcc/descriptors.cpp
// Platform independent layer (PIL) of the USB Device controller driver:
// USB descriptor handling and management.
// 
//

/**
 @file descriptors.cpp
 @internalTechnology
*/

#include <kernel/kern_priv.h>
#include <drivers/usbc.h>


// Debug Support
static const char KUsbPanicCat[] = "USB PIL";


// --- TUsbcDescriptorBase

TUsbcDescriptorBase::TUsbcDescriptorBase()
	:
#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST
	iIndex(0),
#endif
	iBufPtr(NULL, 0)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorBase::TUsbcDescriptorBase()"));
	}


TUsbcDescriptorBase::~TUsbcDescriptorBase()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorBase::~TUsbcDescriptorBase()"));
	}


void TUsbcDescriptorBase::SetByte(TInt aPosition, TUint8 aValue)
	{
	iBufPtr[aPosition] = aValue;
	}


void TUsbcDescriptorBase::SetWord(TInt aPosition, TUint16 aValue)
	{
	*reinterpret_cast<TUint16*>(&iBufPtr[aPosition]) = SWAP_BYTES_16(aValue);
	}


TUint8 TUsbcDescriptorBase::Byte(TInt aPosition) const
	{
	return iBufPtr[aPosition];
	}


TUint16 TUsbcDescriptorBase::Word(TInt aPosition) const
	{
	return SWAP_BYTES_16(*reinterpret_cast<const TUint16*>(&iBufPtr[aPosition]));
	}


void TUsbcDescriptorBase::GetDescriptorData(TDes8& aBuffer) const
	{
	aBuffer = iBufPtr;
	}


TInt TUsbcDescriptorBase::GetDescriptorData(TUint8* aBuffer) const
	{
	memcpy(aBuffer, iBufPtr.Ptr(), Size());
	return Size();
	}


TInt TUsbcDescriptorBase::GetDescriptorData(TUint8* aBuffer, TUint aMaxSize) const
	{
	if (aMaxSize < Size())
		{
		// No use to copy only half a descriptor
		return 0;
		}
	return GetDescriptorData(aBuffer);
	}


const TDes8& TUsbcDescriptorBase::DescriptorData() const
	{
	return iBufPtr;
	}


TDes8& TUsbcDescriptorBase::DescriptorData()
	{
	return iBufPtr;
	}


TUint TUsbcDescriptorBase::Size() const
	{
	return iBufPtr.Size();
	}


TUint8 TUsbcDescriptorBase::Type() const
	{
	return iBufPtr[1];
	}


void TUsbcDescriptorBase::UpdateFs()
	{
	// virtual function can be overridden in derived classes.
	return;
	}


void TUsbcDescriptorBase::UpdateHs()
	{
	// virtual function can be overridden in derived classes.
	return;
	}


void TUsbcDescriptorBase::SetBufferPointer(const TDesC8& aDes)
	{
	iBufPtr.Set(const_cast<TUint8*>(aDes.Ptr()), aDes.Size(), aDes.Size());
	}


// --- TUsbcDeviceDescriptor

TUsbcDeviceDescriptor::TUsbcDeviceDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::TUsbcDeviceDescriptor()"));
	}


TUsbcDeviceDescriptor* TUsbcDeviceDescriptor::New(TUint8 aDeviceClass, TUint8 aDeviceSubClass,
												  TUint8 aDeviceProtocol, TUint8 aMaxPacketSize0,
												  TUint16 aVendorId, TUint16 aProductId,
												  TUint16 aDeviceRelease, TUint8 aNumConfigurations)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::New()"));
	TUsbcDeviceDescriptor* self = new TUsbcDeviceDescriptor();
	if (self)
		{
		if (self->Construct(aDeviceClass, aDeviceSubClass, aDeviceProtocol, aMaxPacketSize0, aVendorId,
							aProductId, aDeviceRelease, aNumConfigurations) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcDeviceDescriptor::Construct(TUint8 aDeviceClass, TUint8 aDeviceSubClass, TUint8 aDeviceProtocol,
									  TUint8 aMaxPacketSize0, TUint16 aVendorId, TUint16 aProductId,
									  TUint16 aDeviceRelease, TUint8 aNumConfigurations)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::Construct()"));
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_Device;							// bDescriptorType
	SetWord(2, KUsbcUsbVersion);							// bcdUSB
	iBuf[4] = aDeviceClass;									// bDeviceClass
	iBuf[5] = aDeviceSubClass;								// bDeviceSubClass
	iBuf[6] = aDeviceProtocol;								// bDeviceProtocol
	iBuf[7] = aMaxPacketSize0;								// bMaxPacketSize0
	SetWord(8, aVendorId);									// idVendor
	SetWord(10, aProductId);								// idProduct
	SetWord(12, aDeviceRelease);							// bcdDevice
	iBuf[14] = 0;											// iManufacturer
	iBuf[15] = 0;											// iProduct
	iBuf[16] = 0;											// iSerialNumber
	iBuf[17] = aNumConfigurations;							// bNumConfigurations
	iEp0Size_Fs = aMaxPacketSize0;
	return KErrNone;
	}


void TUsbcDeviceDescriptor::UpdateFs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::UpdateFs()"));
	SetByte(7, iEp0Size_Fs);								// bMaxPacketSize0
	}


void TUsbcDeviceDescriptor::UpdateHs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::UpdateHs()"));
	SetByte(7, 64);											// bMaxPacketSize0
	}


// --- TUsbcDeviceQualifierDescriptor

TUsbcDeviceQualifierDescriptor::TUsbcDeviceQualifierDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::TUsbcDeviceQualifierDescriptor()"));
	}


TUsbcDeviceQualifierDescriptor* TUsbcDeviceQualifierDescriptor::New(TUint8 aDeviceClass,
																	TUint8 aDeviceSubClass,
																	TUint8 aDeviceProtocol,
																	TUint8 aMaxPacketSize0,
																	TUint8 aNumConfigurations,
																	TUint8 aReserved)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::New()"));
	TUsbcDeviceQualifierDescriptor* self = new TUsbcDeviceQualifierDescriptor();
	if (self)
		{
		if (self->Construct(aDeviceClass, aDeviceSubClass, aDeviceProtocol, aMaxPacketSize0,
							aNumConfigurations, aReserved) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcDeviceQualifierDescriptor::Construct(TUint8 aDeviceClass, TUint8 aDeviceSubClass,
											   TUint8 aDeviceProtocol, TUint8 aMaxPacketSize0,
											   TUint8 aNumConfigurations, TUint8 aReserved)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::Construct()"));
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_DeviceQualifier;					// bDescriptorType
	SetWord(2, KUsbcUsbVersion);							// bcdUSB
	iBuf[4] = aDeviceClass;									// bDeviceClass
	iBuf[5] = aDeviceSubClass;								// bDeviceSubClass
	iBuf[6] = aDeviceProtocol;								// bDeviceProtocol
	iBuf[7] = aMaxPacketSize0;								// bMaxPacketSize0
	iBuf[8] = aNumConfigurations;							// bNumConfigurations
	if (aReserved) aReserved = 0;
	iBuf[9] = aReserved;									// Reserved for future use, must be zero
	iEp0Size_Fs = aMaxPacketSize0;
	return KErrNone;
	}


void TUsbcDeviceQualifierDescriptor::UpdateFs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::UpdateFs()"));
	// Here we do exactly the opposite of what's done in the Device descriptor (as this one's
	// documenting the 'other than the current speed').
	SetByte(7, 64);											// bMaxPacketSize0
	}


void TUsbcDeviceQualifierDescriptor::UpdateHs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::UpdateHs()"));
	// Here we do exactly the opposite of what's done in the Device descriptor (as this one's
	// documenting the 'other than the current speed').
	SetByte(7, iEp0Size_Fs);								// bMaxPacketSize0
	}


// --- TUsbcConfigDescriptor

TUsbcConfigDescriptor::TUsbcConfigDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfigDescriptor::TUsbcConfigDescriptor()"));
	}


TUsbcConfigDescriptor* TUsbcConfigDescriptor::New(TUint8 aConfigurationValue, TBool aSelfPowered,
												  TBool aRemoteWakeup, TUint16 aMaxPower)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfigDescriptor::New()"));
	TUsbcConfigDescriptor* self = new TUsbcConfigDescriptor();
	if (self)
		{
		if (self->Construct(aConfigurationValue, aSelfPowered, aRemoteWakeup, aMaxPower) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcConfigDescriptor::Construct(TUint8 aConfigurationValue, TBool aSelfPowered,
									   TBool aRemoteWakeup, TUint16 aMaxPower)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfigDescriptor::Construct()"));
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_Config;							// bDescriptorType
	SetWord(2, KUsbDescSize_Config);						// wTotalLength
	iBuf[4] = 0;											// bNumInterfaces
	iBuf[5] = aConfigurationValue;							// bConfigurationValue
	iBuf[6] = 0;											// iConfiguration
	iBuf[7] = 0x80 |
		(aSelfPowered ? KUsbDevAttr_SelfPowered : 0) |
		(aRemoteWakeup ? KUsbDevAttr_RemoteWakeup : 0);		// bmAttributes (bit 7 always 1)
	if (aMaxPower > 510)
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Invalid value for bMaxPower: %d", aMaxPower));
	iBuf[8] = aMaxPower / 2;								// bMaxPower (2mA units!)
	return KErrNone;
	}


// --- TUsbcInterfaceDescriptor

TUsbcInterfaceDescriptor::TUsbcInterfaceDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceDescriptor::TUsbcInterfaceDescriptor()"));
	}


TUsbcInterfaceDescriptor* TUsbcInterfaceDescriptor::New(TUint8 aInterfaceNumber, TUint8 aAlternateSetting,
														TInt aNumEndpoints, const TUsbcClassInfo& aClassInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceDescriptor::New()"));
	TUsbcInterfaceDescriptor* self = new TUsbcInterfaceDescriptor();
	if (self)
		{
		if (self->Construct(aInterfaceNumber, aAlternateSetting, aNumEndpoints, aClassInfo) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcInterfaceDescriptor::Construct(TUint8 aInterfaceNumber, TUint8 aAlternateSetting,
										 TInt aNumEndpoints, const TUsbcClassInfo& aClassInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceDescriptor::Construct()"));
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_Interface;						// bDescriptorType
	iBuf[2] = aInterfaceNumber;								// bInterfaceNumber
	iBuf[3] = aAlternateSetting;							// bAlternateSetting
	iBuf[4] = aNumEndpoints;								// bNumEndpoints
	iBuf[5] = aClassInfo.iClassNum;							// bInterfaceClass
	iBuf[6] = aClassInfo.iSubClassNum;						// bInterfaceSubClass
	iBuf[7] = aClassInfo.iProtocolNum;						// bInterfaceProtocol
	iBuf[8] = 0;											// iInterface
	return KErrNone;
	}


// --- TUsbcEndpointDescriptorBase

TUsbcEndpointDescriptorBase::TUsbcEndpointDescriptorBase()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::TUsbcEndpointDescriptorBase()"));
	}


TInt TUsbcEndpointDescriptorBase::Construct(const TUsbcEndpointInfo& aEpInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::Construct()"));
	//  Adjust FS/HS endpoint sizes
	if (aEpInfo.AdjustEpSizes(iEpSize_Fs, iEpSize_Hs) != KErrNone)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Unknown endpoint type: %d", aEpInfo.iType));
		}
	__KTRACE_OPT(KUSB, Kern::Printf("  Now set: iEpSize_Fs=%d iEpSize_Hs=%d (aEpInfo.iSize=%d)",
									iEpSize_Fs, iEpSize_Hs, aEpInfo.iSize));

	//  Adjust HS endpoint size for additional transactions
	if ((aEpInfo.iType == KUsbEpTypeIsochronous) || (aEpInfo.iType == KUsbEpTypeInterrupt))
		{
		if ((aEpInfo.iTransactions > 0) && (aEpInfo.iTransactions < 3))
			{
			// Bits 12..11 specify the number of additional transactions per microframe
			iEpSize_Hs |= (aEpInfo.iTransactions << 12);
			__KTRACE_OPT(KUSB, Kern::Printf("  Adjusted for add. transact.: iEpSize_Hs=0x%02x "
											"(aEpInfo.iTransactions=%d)",
											iEpSize_Hs, aEpInfo.iTransactions));
			}
		else if (aEpInfo.iTransactions != 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: Invalid iTransactions value: %d (ignored)",
											  aEpInfo.iTransactions));
			}
		}

	//  Adjust HS polling interval
	TUsbcEndpointInfo info(aEpInfo);						// create local writeable copy
	if (info.AdjustPollInterval() != KErrNone)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Unknown ep type (%d) or invalid interval value (%d)",
										  info.iType, info.iInterval));
		}
	iInterval_Fs = info.iInterval;
	iInterval_Hs = info.iInterval_Hs;
	__KTRACE_OPT(KUSB, Kern::Printf("  Now set: iInterval_Fs=%d iInterval_Hs=%d",
									iInterval_Fs, iInterval_Hs));
	return KErrNone;
	}


void TUsbcEndpointDescriptorBase::UpdateFs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::UpdateFs()"));
	// (TUsbcEndpointDescriptorBase's FS/HS endpoint sizes and interval values got
	//  adjusted in its Construct() method.)
	SetWord(4, iEpSize_Fs);									// wMaxPacketSize
	SetByte(6, iInterval_Fs);								// bInterval
	}


void TUsbcEndpointDescriptorBase::UpdateHs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::UpdateHs()"));
	// (TUsbcEndpointDescriptorBase's FS/HS endpoint sizes and interval values get
	//  adjusted in its Construct() method.)
	SetWord(4, iEpSize_Hs);									// wMaxPacketSize
	SetByte(6, iInterval_Hs);								// bInterval
	}


// --- TUsbcEndpointDescriptor

TUsbcEndpointDescriptor::TUsbcEndpointDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptor::TUsbcEndpointDescriptor()"));
	}


TUsbcEndpointDescriptor* TUsbcEndpointDescriptor::New(TUint8 aEndpointAddress,
													  const TUsbcEndpointInfo& aEpInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptor::New()"));
	TUsbcEndpointDescriptor* self = new TUsbcEndpointDescriptor();
	if (self)
		{
		if (self->Construct(aEndpointAddress, aEpInfo) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcEndpointDescriptor::Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptor::Construct()"));
	(void) TUsbcEndpointDescriptorBase::Construct(aEpInfo);	// Init Base class
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_Endpoint;						// bDescriptorType
	iBuf[2] = aEndpointAddress;								// bEndpointAddress
	iBuf[3] = EpTypeMask2Value(aEpInfo.iType);				// bmAttributes
	SetWord(4, iEpSize_Fs);									// wMaxPacketSize (default is FS)
	iBuf[6] = iInterval_Fs;									// bInterval (default is FS)
	return KErrNone;
	}


// --- TUsbcAudioEndpointDescriptor

TUsbcAudioEndpointDescriptor::TUsbcAudioEndpointDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcAudioEndpointDescriptor::TUsbcAudioEndpointDescriptor()"));
	}


TUsbcAudioEndpointDescriptor* TUsbcAudioEndpointDescriptor::New(TUint8 aEndpointAddress,
																const TUsbcEndpointInfo& aEpInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcAudioEndpointDescriptor::New()"));
	TUsbcAudioEndpointDescriptor* self = new TUsbcAudioEndpointDescriptor();
	if (self)
		{
		if (self->Construct(aEndpointAddress, aEpInfo) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcAudioEndpointDescriptor::Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcAudioEndpointDescriptor::Construct()"));
	(void) TUsbcEndpointDescriptorBase::Construct(aEpInfo);	// Init Base class
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_Endpoint;						// bDescriptorType
	iBuf[2] = aEndpointAddress;								// bEndpointAddress
	iBuf[3] = EpTypeMask2Value(aEpInfo.iType);				// bmAttributes
	SetWord(4, iEpSize_Fs);									// wMaxPacketSize (default is FS)
	iBuf[6] = iInterval_Fs;									// bInterval (default is FS)
	iBuf[7] = 0;
	iBuf[8] = 0;
	return KErrNone;
	}


// --- TUsbcOtgDescriptor

TUsbcOtgDescriptor* TUsbcOtgDescriptor::New(TBool aHnpSupport, TBool aSrpSupport)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcOtgDescriptor::New()"));
	TUsbcOtgDescriptor* self = new TUsbcOtgDescriptor();
	if (self && (self->Construct(aHnpSupport, aSrpSupport) != KErrNone))
		{
		delete self;
		return NULL;
		}
	return self;
	}


TUsbcOtgDescriptor::TUsbcOtgDescriptor()
	: iBuf()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcOtgDescriptor::TUsbcOtgDescriptor()"));
	}


TInt TUsbcOtgDescriptor::Construct(TBool aHnpSupport, TBool aSrpSupport)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcOtgDescriptor::Construct()"));
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBuf[0] = iBuf.Size();									// bLength
	iBuf[1] = KUsbDescType_Otg;								// bDescriptorType
	iBuf[2] = (aHnpSupport ? KUsbOtgAttr_HnpSupp : 0) |
		(aSrpSupport ? KUsbOtgAttr_SrpSupp : 0);			// bmAttributes
	return KErrNone;
    }


// --- TUsbcClassSpecificDescriptor

TUsbcClassSpecificDescriptor::TUsbcClassSpecificDescriptor()
	: iBuf(NULL)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::TUsbcClassSpecificDescriptor()"));
	}


TUsbcClassSpecificDescriptor::~TUsbcClassSpecificDescriptor()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::~TUsbcClassSpecificDescriptor()"));
	delete iBuf;
	}


TUsbcClassSpecificDescriptor* TUsbcClassSpecificDescriptor::New(TUint8 aType, TInt aSize)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::New()"));
	TUsbcClassSpecificDescriptor* self = new TUsbcClassSpecificDescriptor();
	if (self)
		{
		if (self->Construct(aType, aSize) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcClassSpecificDescriptor::Construct(TUint8 aType, TInt aSize)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::Construct()"));
	iBuf = HBuf8::New(aSize);
	if (!iBuf)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Allocation of CS desc buffer failed"));
		return KErrNoMemory;
		}
	iBuf->SetMax();
	SetBufferPointer(*iBuf);
	SetByte(1, aType);										// bDescriptorType
	return KErrNone;
	}


// --- TUsbcStringDescriptorBase

TUsbcStringDescriptorBase::TUsbcStringDescriptorBase()
	: /*iIndex(0),*/ iSBuf(0), iBufPtr(NULL, 0)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptorBase::TUsbcStringDescriptorBase()"));
	}


TUsbcStringDescriptorBase::~TUsbcStringDescriptorBase()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptorBase::~TUsbcStringDescriptorBase()"));
	}


TUint16 TUsbcStringDescriptorBase::Word(TInt aPosition) const
	{
	if (aPosition <= 1)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Word(%d) in string descriptor "
										  "(TUsbcStringDescriptorBase::Word)", aPosition));
		return 0;
		}
	else
		{
		// since iBufPtr[0] is actually string descriptor byte index 2,
		// we have to subtract 2 from the absolute position.
		return SWAP_BYTES_16(*reinterpret_cast<const TUint16*>(&iBufPtr[aPosition - 2]));
		}
	}


void TUsbcStringDescriptorBase::SetWord(TInt aPosition, TUint16 aValue)
	{
	if (aPosition <= 1)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: SetWord(%d) in string descriptor "
										  "(TUsbcStringDescriptorBase::SetWord)", aPosition));
		return;
		}
	else
		{
		// since iBufPtr[0] is actually string descriptor byte index 2,
		// we have to subtract 2 from the absolute position.
		*reinterpret_cast<TUint16*>(&iBufPtr[aPosition - 2]) = SWAP_BYTES_16(aValue);
		}
	}


TInt TUsbcStringDescriptorBase::GetDescriptorData(TUint8* aBuffer) const
	{
	aBuffer[0] = iSBuf[0];
	aBuffer[1] = iSBuf[1];
	memcpy(&aBuffer[2], iBufPtr.Ptr(), iBufPtr.Size());
	return Size();
	}


TInt TUsbcStringDescriptorBase::GetDescriptorData(TUint8* aBuffer, TUint aMaxSize) const
	{
	if (aMaxSize < Size())
		{
		// No use to copy only half a string
		return 0;
		}
	return GetDescriptorData(aBuffer);
	}


const TDes8& TUsbcStringDescriptorBase::StringData() const
	{
	return iBufPtr;
	}


TDes8& TUsbcStringDescriptorBase::StringData()
	{
	return iBufPtr;
	}


TUint TUsbcStringDescriptorBase::Size() const
	{
	return iSBuf[0];
	}


void TUsbcStringDescriptorBase::SetBufferPointer(const TDesC8& aDes)
	{
	iBufPtr.Set(const_cast<TUint8*>(aDes.Ptr()), aDes.Size(), aDes.Size());
	}


// --- TUsbcStringDescriptor

TUsbcStringDescriptor::TUsbcStringDescriptor()
	: iBuf(NULL)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::TUsbcStringDescriptor()"));
	}


TUsbcStringDescriptor::~TUsbcStringDescriptor()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::~TUsbcStringDescriptor()"));
	delete iBuf;
	}


TUsbcStringDescriptor* TUsbcStringDescriptor::New(const TDesC8& aString)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::New"));
	TUsbcStringDescriptor* self = new TUsbcStringDescriptor();
	if (self)
		{
		if (self->Construct(aString) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcStringDescriptor::Construct(const TDesC8& aString)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::Construct"));
	iBuf = HBuf8::New(aString.Size());						// bytes, not UNICODE chars
	if (!iBuf)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Allocation of string buffer failed"));
		return KErrNoMemory;
		}
	iBuf->SetMax();
	SetBufferPointer(*iBuf);
	iBufPtr.Copy(aString);
	iSBuf.SetMax();
	iSBuf[0] = iBuf->Size() + 2;							// Bytes
	iSBuf[1] = KUsbDescType_String;
	return KErrNone;
	}


// --- TUsbcLangIdDescriptor

TUsbcLangIdDescriptor::TUsbcLangIdDescriptor()
	: iBuf(NULL)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::TUsbcLangIdDescriptor()"));
	}


TUsbcLangIdDescriptor::~TUsbcLangIdDescriptor()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::~TUsbcLangIdDescriptor()"));
	}


TUsbcLangIdDescriptor* TUsbcLangIdDescriptor::New(TUint16 aLangId)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::New"));
	TUsbcLangIdDescriptor* self = new TUsbcLangIdDescriptor();
	if (self)
		{
		if (self->Construct(aLangId) != KErrNone)
			{
			delete self;
			return NULL;
			}
		}
	return self;
	}


TInt TUsbcLangIdDescriptor::Construct(TUint16 aLangId)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::Construct"));
	iBuf.SetMax();
	SetBufferPointer(iBuf);
	iBufPtr[0] = LowByte(SWAP_BYTES_16(aLangId));			// Language ID value
	iBufPtr[1] = HighByte(SWAP_BYTES_16(aLangId));
	iSBuf.SetMax();
	iSBuf[0] = iBuf.Size() + 2;								// Bytes
	iSBuf[1] = KUsbDescType_String;
	return KErrNone;
	}


// --- TUsbcDescriptorPool

TUsbcDescriptorPool::TUsbcDescriptorPool(TUint8* aEp0_TxBuf)
//
//	The constructor for this class.
//
	: iDescriptors(), iStrings(), iIfcIdx(0), iEp0_TxBuf(aEp0_TxBuf), iHighSpeed(EFalse)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::TUsbcDescriptorPool()"));
	}


TUsbcDescriptorPool::~TUsbcDescriptorPool()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::~TUsbcDescriptorPool()"));
	// The destructor of each <class T> object is called before the objects themselves are destroyed.
	__KTRACE_OPT(KUSB, Kern::Printf("  iDescriptors.Count(): %d", iDescriptors.Count()));
	iDescriptors.ResetAndDestroy();
	__KTRACE_OPT(KUSB, Kern::Printf("  iStrings.Count(): %d", iStrings.Count()));
	iStrings.ResetAndDestroy();
	}


TInt TUsbcDescriptorPool::Init(TUsbcDeviceDescriptor* aDeviceDesc, TUsbcConfigDescriptor* aConfigDesc,
							   TUsbcLangIdDescriptor* aLangId, TUsbcStringDescriptor* aManufacturer,
							   TUsbcStringDescriptor* aProduct, TUsbcStringDescriptor* aSerialNum,
							   TUsbcStringDescriptor* aConfig, TUsbcOtgDescriptor* aOtgDesc)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::Init()"));
	if (!aDeviceDesc || !aConfigDesc)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: No Device or Config descriptor specified"));
		return KErrArgument;
		}
	for (TInt n = 0; n < KDescPosition_FirstAvailable; n++)
		{
		iDescriptors.Append(NULL);
		}
	__ASSERT_DEBUG((iDescriptors.Count() == KDescPosition_FirstAvailable),
				   Kern::Printf("  Error: iDescriptors.Count() (%d) != KDescPosition_FirstAvailable (%d)",
								iDescriptors.Count(), KDescPosition_FirstAvailable));
	iDescriptors[KDescPosition_Device] = aDeviceDesc;
	iDescriptors[KDescPosition_Config] = aConfigDesc;
	if (aOtgDesc)
		{
		iDescriptors[KDescPosition_Otg] = aOtgDesc;
		// Update the config descriptor's wTotalLength field
		UpdateConfigDescriptorLength(KUsbDescSize_Otg);
		}
	if (!aLangId)
		{
		// USB spec 9.6.7 says: "String index zero for all languages returns a string descriptor
		// that contains an array of two-byte LANGID codes supported by the device. ...
		// USB devices that omit all string descriptors must not return an array of LANGID codes."
		// So if we have at least one string descriptor, we must also have a LANGID descriptor.
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: No LANGID string descriptor specified"));
		return KErrArgument;
		}
	iStrings.Insert(aLangId, KStringPosition_Langid);
	iStrings.Insert(aManufacturer, KStringPosition_Manufact);
	iStrings.Insert(aProduct, KStringPosition_Product);
	iStrings.Insert(aSerialNum, KStringPosition_Serial);
	iStrings.Insert(aConfig, KStringPosition_Config);
	__ASSERT_DEBUG((iStrings.Count() == 5),
				   Kern::Printf("  Error: iStrings.Count() != 5 (%d)", iStrings.Count()));
#ifdef _DEBUG
	for (TInt i = KStringPosition_Langid; i <= KStringPosition_Config; i++)
		{
		__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool.iStrings[%d] = 0x%x", i, iStrings[i]));
		}
#endif
	// Set string indices
	if (aManufacturer)
		iDescriptors[KDescPosition_Device]->SetByte(KUsbDescStringIndex_Manufact,
													KStringPosition_Manufact);
	if (aProduct)
		iDescriptors[KDescPosition_Device]->SetByte(KUsbDescStringIndex_Product,
													KStringPosition_Product);
	if (aSerialNum)
		iDescriptors[KDescPosition_Device]->SetByte(KUsbDescStringIndex_Serial,
													KStringPosition_Serial);
	if (aConfig)
		iDescriptors[KDescPosition_Config]->SetByte(KUsbDescStringIndex_Config,
													KStringPosition_Config);
	return KErrNone;
	}


TInt TUsbcDescriptorPool::InitHs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InitHs()"));
	__ASSERT_DEBUG((iDescriptors.Count() >= KDescPosition_FirstAvailable),
				   Kern::Printf("  Error: Call Init() first)"));

	TUsbcDeviceQualifierDescriptor* const dq_desc = TUsbcDeviceQualifierDescriptor::New(
		iDescriptors[KDescPosition_Device]->Byte(4),		// aDeviceClass
		iDescriptors[KDescPosition_Device]->Byte(5),		// aDeviceSubClass
		iDescriptors[KDescPosition_Device]->Byte(6),		// aDeviceProtocol
		iDescriptors[KDescPosition_Device]->Byte(7),		// aMaxPacketSize0
		iDescriptors[KDescPosition_Device]->Byte(17));		// aNumConfigurations
	if (!dq_desc)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Memory allocation for dev qualif desc failed."));
		return KErrGeneral;
		}
	iDescriptors[KDescPosition_DeviceQualifier] = dq_desc;

	TUsbcOtherSpeedConfigDescriptor* const osc_desc = TUsbcOtherSpeedConfigDescriptor::New(
		iDescriptors[KDescPosition_Config]->Byte(5),		// aConfigurationValue
		iDescriptors[KDescPosition_Config]->Byte(7) & KUsbDevAttr_SelfPowered, // aSelfPowered
		iDescriptors[KDescPosition_Config]->Byte(7) & KUsbDevAttr_RemoteWakeup,	// aRemoteWakeup
		iDescriptors[KDescPosition_Config]->Byte(8) * 2);	// aMaxPower (mA)
	if (!osc_desc)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Memory allocation for other speed conf desc failed."));
		return KErrGeneral;
		}

	// We need to set the bDescriptorType field manually, as that's the only one
	// that differs from a Configuration descriptor.
	osc_desc->SetByte(1, KUsbDescType_OtherSpeedConfig);

	// Also, initially we set the iConfiguration string index to the same value as
	// in the Configuration descriptor.
	osc_desc->SetByte(KUsbDescStringIndex_Config,
					  iDescriptors[KDescPosition_Config]->Byte(KUsbDescStringIndex_Config));

	iDescriptors[KDescPosition_OtherSpeedConfig] = osc_desc;

	return KErrNone;
	}


TInt TUsbcDescriptorPool::UpdateDescriptorsFs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateDescriptorsFs()"));
	const TInt count = iDescriptors.Count();
	for (TInt i = KDescPosition_FirstAvailable; i < count; i++)
		{
		TUsbcDescriptorBase* const ptr = iDescriptors[i];
		ptr->UpdateFs();
		}
	iHighSpeed = EFalse;
	return KErrNone;
	}


TInt TUsbcDescriptorPool::UpdateDescriptorsHs()
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateDescriptorsHs()"));
	const TInt count = iDescriptors.Count();
	for (TInt i = KDescPosition_FirstAvailable; i < count; i++)
		{
		TUsbcDescriptorBase* const ptr = iDescriptors[i];
		ptr->UpdateHs();
		}
	iHighSpeed = ETrue;
	return KErrNone;
	}


//
// An error can be indicated by either a return value != KErrNone or by a descriptor size == 0.
//
TInt TUsbcDescriptorPool::FindDescriptor(TUint8 aType, TUint8 aIndex, TUint16 aLangid, TInt& aSize) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindDescriptor()"));
	TInt result = KErrGeneral;
	switch (aType)
		{
	case KUsbDescType_Device:
		if (aLangid != 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad langid: 0x%04x", aLangid));
			}
		else if (aIndex > 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad device index: %d", aIndex));
			}
		else
			{
			aSize = GetDeviceDescriptor(KDescPosition_Device);
			result = KErrNone;
			}
		break;
	case KUsbDescType_Config:
		if (aLangid != 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad langid: 0x%04x", aLangid));
			}
		else if (aIndex > 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad config index: %d", aIndex));
			}
		else
			{
			aSize = GetConfigurationDescriptor(KDescPosition_Config);
			result = KErrNone;
			}
		break;
	case KUsbDescType_DeviceQualifier:
		if (aLangid != 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad langid: 0x%04x", aLangid));
			}
		else if (aIndex > 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad device index: %d", aIndex));
			}
		else
			{
			aSize = GetDeviceDescriptor(KDescPosition_DeviceQualifier);
			result = KErrNone;
			}
		break;
	case KUsbDescType_OtherSpeedConfig:
		if (aLangid != 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad langid: 0x%04x", aLangid));
			}
		else if (aIndex > 0)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bad config index: %d", aIndex));
			}
		else
			{
			aSize = GetConfigurationDescriptor(KDescPosition_OtherSpeedConfig);
			result = KErrNone;
			}
		break;
	case KUsbDescType_Otg:
		aSize = GetOtgDescriptor();
		result = KErrNone;
		break;
	case KUsbDescType_String:
		if (aIndex == 0)									// 0 addresses the LangId array
			{
			if (AnyStringDescriptors())
				{
				aSize = GetStringDescriptor(aIndex);
				result = KErrNone;
				}
			else
				{
				__KTRACE_OPT(KUSB, Kern::Printf("  No string descriptors: not returning LANGID array"));
				}
			}
		else
			{
   			if (!aLangid)
   				{
   				__KTRACE_OPT(KUSB,
 							 Kern::Printf("  Strange: LANGID=0 for a $ descriptor (ignoring LANGID)"));
				// The USB spec doesn't really say what to do in this case, but as there are host apps
				// that fail if we return an error here, we choose to ignore the issue.
   				}
			else if (aLangid != iStrings[KStringPosition_Langid]->Word(2))
				{
				// We have only one (this) language
				__KTRACE_OPT(KUSB,
							 Kern::Printf("  Bad LANGID: 0x%04X requested, 0x%04X supported (ignoring LANGID)",
										  aLangid, iStrings[KStringPosition_Langid]->Word(2)));
				// We could return an error here, but rather choose to ignore the discrepancy
				// (the USB spec is not very clear what to do in such a case anyway).
				}
			aSize = GetStringDescriptor(aIndex);
			result = KErrNone;
			}
		break;
	case KUsbDescType_CS_Interface:
		/* fall through */
	case KUsbDescType_CS_Endpoint:
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: finding of class specific descriptors not supported"));
		break;
	default:
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: unknown descriptor type requested: %d", aType));
		break;
		}
	return result;
	}


void TUsbcDescriptorPool::InsertDescriptor(TUsbcDescriptorBase* aDesc)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InsertDescriptor()"));
	switch (aDesc->Type())
		{
	case KUsbDescType_Interface:
		InsertIfcDesc(aDesc);
		break;
	case KUsbDescType_Endpoint:
		InsertEpDesc(aDesc);
		break;
	default:
		__KTRACE_OPT(KUSB, Kern::Printf("  Error: unsupported descriptor type"));
		}
	}


void TUsbcDescriptorPool::SetIfcStringDescriptor(TUsbcStringDescriptor* aDesc, TInt aNumber, TInt aSetting)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetIfcDescriptor(%d, %d)", aNumber, aSetting));
	const TInt i = FindIfcDescriptor(aNumber, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Ifc descriptor not found (%d, %d)",
										  aNumber, aSetting));
		return;
		}
	// Try to find available NULL postition
	TInt str_idx = FindAvailableStringPos();
	if (str_idx >= 0)
		{
		// Insert string descriptor for specified interface
		ExchangeStringDescriptor(str_idx, aDesc);
		}
	else
		{
		// No NULL found - expand array
		str_idx = iStrings.Count();
		if (str_idx > 0xff)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: $ descriptor array full (idx=%d)", str_idx));
			return;
			}
		while (str_idx < KStringPosition_FirstAvailable)
			{
			iStrings.Append(NULL);
			str_idx = iStrings.Count();
			}
		// Append string descriptor for specified interface
		iStrings.Append(aDesc);
		}
	// Update this ifc descriptor's string index field
	iDescriptors[i]->SetByte(8, str_idx);
	__KTRACE_OPT(KUSB, Kern::Printf("  String for ifc %d/%d (@ pos %d): \"%S\"", aNumber, aSetting, str_idx,
									&iStrings[str_idx]->StringData()));
	}


void TUsbcDescriptorPool::DeleteIfcDescriptor(TInt aNumber, TInt aSetting)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::DeleteIfcDescriptor(%d, %d)", aNumber, aSetting));
	const TInt i = FindIfcDescriptor(aNumber, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: DeleteIfcDescriptor - descriptor not found (%d, %d)",
										  aNumber, aSetting));
		return;
		}
	// Delete (if necessary) specified interface's string descriptor
	const TInt si = iDescriptors[i]->Byte(8);
	if (si != 0)
		{
		ExchangeStringDescriptor(si, NULL);
		}
	// Delete specified ifc setting + all its cs descriptors + all its endpoints + all their cs descriptors:
	// find position of the next interface descriptor: we need to delete everything in between
	const TInt count = iDescriptors.Count();
	TInt j = i, n = 1;
	while (++j < count && iDescriptors[j]->Type() != KUsbDescType_Interface)
		++n;
	DeleteDescriptors(i, n);
	// Update all the following interfaces' bInterfaceNumber field if required
	// (because those descriptors might have moved down by one position)
	UpdateIfcNumbers(aNumber);
	iIfcIdx = 0;											// ifc index no longer valid
	}


// The TC in many of the following functions stands for 'ThreadCopy',
// because that's what's happening there.

TInt TUsbcDescriptorPool::GetDeviceDescriptorTC(DThread* aThread, TDes8& aBuffer) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceDescriptorTC()"));
	return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[KDescPosition_Device]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetDeviceDescriptorTC(DThread* aThread, const TDes8& aBuffer)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetDeviceDescriptorTC()"));
	TBuf8<KUsbDescSize_Device> device;
	const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, device, 0);
	if (r != KErrNone)
		{
		return r;
		}
	iDescriptors[KDescPosition_Device]->SetByte(2, device[2]); // bcdUSB
	iDescriptors[KDescPosition_Device]->SetByte(3, device[3]); // bcdUSB (part II)
	iDescriptors[KDescPosition_Device]->SetByte(4, device[4]); // bDeviceClass
	iDescriptors[KDescPosition_Device]->SetByte(5, device[5]); // bDeviceSubClass
	iDescriptors[KDescPosition_Device]->SetByte(6, device[6]); // bDeviceProtocol
	iDescriptors[KDescPosition_Device]->SetByte(8, device[8]); // idVendor
	iDescriptors[KDescPosition_Device]->SetByte(9, device[9]); // idVendor (part II)
	iDescriptors[KDescPosition_Device]->SetByte(10, device[10]); // idProduct
	iDescriptors[KDescPosition_Device]->SetByte(11, device[11]); // idProduct (part II)
	iDescriptors[KDescPosition_Device]->SetByte(12, device[12]); // bcdDevice
	iDescriptors[KDescPosition_Device]->SetByte(13, device[13]); // bcdDevice (part II)
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetConfigurationDescriptorTC(DThread* aThread, TDes8& aBuffer) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetConfigurationDescriptorTC()"));
	return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[KDescPosition_Config]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetConfigurationDescriptorTC(DThread* aThread, const TDes8& aBuffer)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetConfigurationDescriptorTC()"));
	TBuf8<KUsbDescSize_Config> config;
	const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, config, 0);
	if (r != KErrNone)
		{
		return r;
		}
	iDescriptors[KDescPosition_Config]->SetByte(7, config[7]); // bmAttributes
	iDescriptors[KDescPosition_Config]->SetByte(8, config[8]); // bMaxPower
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetOtgDescriptorTC(DThread* aThread, TDes8& aBuffer) const
	{
	return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[KDescPosition_Otg]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetOtgDescriptor(const TDesC8& aBuffer)
	{
	iDescriptors[KDescPosition_Otg]->SetByte(2, aBuffer[2]); // bmAttributes
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetInterfaceDescriptorTC(DThread* aThread, TDes8& aBuffer,
												   TInt aInterface, TInt aSetting) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetInterfaceDescriptorTC()"));
	const TInt i = FindIfcDescriptor(aInterface, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
		return KErrNotFound;
		}
	return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetInterfaceDescriptor(const TDes8& aBuffer, TInt aInterface, TInt aSetting)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetInterfaceDescriptor()"));
	const TInt i = FindIfcDescriptor(aInterface, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
		return KErrNotFound;
		}
	iDescriptors[i]->SetByte(2, aBuffer[2]);				// bInterfaceNumber
	iDescriptors[i]->SetByte(5, aBuffer[5]);				// bInterfaceClass
	iDescriptors[i]->SetByte(6, aBuffer[6]);				// bInterfaceSubClass
	iDescriptors[i]->SetByte(7, aBuffer[7]);				// bInterfaceProtocol
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetEndpointDescriptorTC(DThread* aThread, TDes8& aBuffer,
												  TInt aInterface, TInt aSetting, TUint8 aEndpointAddress) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetEndpointDescriptorTC()"));
	const TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
		return KErrNotFound;
		}
	return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetEndpointDescriptorTC(DThread* aThread, const TDes8& aBuffer,
												  TInt aInterface, TInt aSetting, TUint8 aEndpointAddress)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetEndpointDescriptorTC()"));
	const TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
		return KErrNotFound;
		}
	TBuf8<KUsbDescSize_AudioEndpoint> ep;					// it could be an audio endpoint
	const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, ep, 0);
	if (r != KErrNone)
		{
		return r;
		}
	iDescriptors[i]->SetByte(3, ep[3]);						// bmAttributes
	iDescriptors[i]->SetByte(6, ep[6]);						// bInterval
	if (iDescriptors[i]->Size() == KUsbDescSize_AudioEndpoint)
		{
		iDescriptors[i]->SetByte(7, ep[7]);					// bRefresh
		iDescriptors[i]->SetByte(8, ep[8]);					// bSynchAddress
		}
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetEndpointDescriptorSize(TInt aInterface, TInt aSetting, TUint8 aEndpointAddress,
													TInt& aSize) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetEndpointDescriptorSize()"));
	const TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
		return KErrNotFound;
		}
	aSize = iDescriptors[i]->Size();
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetDeviceQualifierDescriptorTC(DThread* aThread, TDes8& aBuffer) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceQualifierDescriptorTC()"));
	if (iDescriptors[KDescPosition_DeviceQualifier] == NULL)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: Device_Qualifier descriptor not supported"));
		return KErrNotSupported;
		}
	return Kern::ThreadDesWrite(aThread, &aBuffer,
								iDescriptors[KDescPosition_DeviceQualifier]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetDeviceQualifierDescriptorTC(DThread* aThread, const TDes8& aBuffer)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetDeviceQualifierDescriptorTC()"));
	if (iDescriptors[KDescPosition_DeviceQualifier] == NULL)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: Device_Qualifier descriptor not supported"));
		return KErrNotSupported;
		}
	TBuf8<KUsbDescSize_DeviceQualifier> device;
	const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, device, 0);
	if (r != KErrNone)
		{
		return r;
		}
	iDescriptors[KDescPosition_DeviceQualifier]->SetByte(2, device[2]); // bcdUSB
	iDescriptors[KDescPosition_DeviceQualifier]->SetByte(3, device[3]); // bcdUSB (part II)
	iDescriptors[KDescPosition_DeviceQualifier]->SetByte(4, device[4]); // bDeviceClass
	iDescriptors[KDescPosition_DeviceQualifier]->SetByte(5, device[5]); // bDeviceSubClass
	iDescriptors[KDescPosition_DeviceQualifier]->SetByte(6, device[6]); // bDeviceProtocol
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetOtherSpeedConfigurationDescriptorTC(DThread* aThread, TDes8& aBuffer) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetOtherSpeedConfigurationDescriptorTC()"));
	if (iDescriptors[KDescPosition_OtherSpeedConfig] == NULL)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: Other_Speed_Configuration descriptor not supported"));
		return KErrNotSupported;
		}
	return Kern::ThreadDesWrite(aThread, &aBuffer,
								iDescriptors[KDescPosition_OtherSpeedConfig]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::SetOtherSpeedConfigurationDescriptorTC(DThread* aThread, const TDes8& aBuffer)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetOtherSpeedConfigurationDescriptorTC()"));
	if (iDescriptors[KDescPosition_OtherSpeedConfig] == NULL)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: Other_Speed_Configuration descriptor not supported"));
		return KErrNotSupported;
		}
	TBuf8<KUsbDescSize_OtherSpeedConfig> config;
	const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, config, 0);
	if (r != KErrNone)
		{
		return r;
		}
	iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(7, config[7]); // bmAttributes
	iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(8, config[8]); // bMaxPower
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetCSInterfaceDescriptorTC(DThread* aThread, TDes8& aBuffer,
													 TInt aInterface, TInt aSetting) const
	{
	// first find the interface
	TInt i = FindIfcDescriptor(aInterface, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
		return KErrNotFound;
		}
	TInt r = KErrNotFound;
	TInt offset = 0;
	const TInt count = iDescriptors.Count();
	while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Interface)
		{
		r = Kern::ThreadDesWrite(aThread, &aBuffer,
								 iDescriptors[i]->DescriptorData(), offset);
		if (r != KErrNone)
			break;
		offset += iDescriptors[i]->Size();
		}
	return r;
	}


TInt TUsbcDescriptorPool::SetCSInterfaceDescriptorTC(DThread* aThread, const TDes8& aBuffer,
													 TInt aInterface, TInt aSetting, TInt aSize)
	{
	// First find the interface
	TInt i = FindIfcDescriptor(aInterface, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
		return KErrNotFound;
		}
	// Find a position where to insert the new class specific interface descriptor(s)
	const TInt count = iDescriptors.Count();
	while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Interface)
		;
	// Create a new cs descriptor
	TUsbcClassSpecificDescriptor* desc = TUsbcClassSpecificDescriptor::New(KUsbDescType_CS_Interface, aSize);
	if (!desc)
		{
		return KErrNoMemory;
		}
	__KTRACE_OPT(KUSB, Kern::Printf("  inserting descriptor at position %d", i));
	iDescriptors.Insert(desc, i);

	// Update the config descriptor's wTotalLength field
	UpdateConfigDescriptorLength(aSize);

	// Copy contents from the user side
	return Kern::ThreadDesRead(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::GetCSInterfaceDescriptorSize(TInt aInterface, TInt aSetting, TInt& aSize) const
	{
	// first find the interface
	TInt i = FindIfcDescriptor(aInterface, aSetting);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
		return KErrNotFound;
		}
	TInt r = KErrNotFound;
	TInt size = 0;
	const TInt count = iDescriptors.Count();
	while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Interface)
		{
		size += iDescriptors[i]->Size();
		r = KErrNone;
		}
	if (r == KErrNone)
		aSize = size;
	return r;
	}


TInt TUsbcDescriptorPool::GetCSEndpointDescriptorTC(DThread* aThread, TDes8& aBuffer, TInt aInterface,
													TInt aSetting, TUint8 aEndpointAddress) const
	{
	// first find the endpoint
	TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
		return KErrNotFound;
		}
	TInt r = KErrNotFound;
	TInt offset = 0;
	const TInt count = iDescriptors.Count();
	while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Endpoint)
		{
		r = Kern::ThreadDesWrite(aThread, &aBuffer,
								 iDescriptors[i]->DescriptorData(), offset);
		if (r != KErrNone)
			break;
		offset += iDescriptors[i]->Size();
		}
	return r;
	}


TInt TUsbcDescriptorPool::SetCSEndpointDescriptorTC(DThread* aThread, const TDes8& aBuffer, TInt aInterface,
													TInt aSetting, TUint8 aEndpointAddress, TInt aSize)
	{
	// first find the endpoint
	TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
		return KErrNotFound;
		}
	// find a position where to insert the new class specific endpoint descriptor(s)
	const TInt count = iDescriptors.Count();
	while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Endpoint)
		;
	// create a new cs descriptor
	TUsbcClassSpecificDescriptor* desc = TUsbcClassSpecificDescriptor::New(KUsbDescType_CS_Endpoint, aSize);
	if (!desc)
		{
		return KErrNoMemory;
		}
	iDescriptors.Insert(desc, i);
	// update the config descriptor's wTotalLength field
	UpdateConfigDescriptorLength(aSize);
	// copy contents from user side
	return Kern::ThreadDesRead(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0);
	}


TInt TUsbcDescriptorPool::GetCSEndpointDescriptorSize(TInt aInterface, TInt aSetting,
													  TUint8 aEndpointAddress, TInt& aSize) const
	{
	// first find the endpoint
	TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress);
	if (i < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
		return KErrNotFound;
		}
	TInt r = KErrNotFound;
	TInt size = 0;
	const TInt count = iDescriptors.Count();
	while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Endpoint)
		{
		size += iDescriptors[i]->Size();
		r = KErrNone;
		}
	if (r == KErrNone)
		aSize = size;
	return r;
	}


TInt TUsbcDescriptorPool::GetStringDescriptorLangIdTC(DThread* aThread, TDes8& aLangId) const
	{
	const TUint16 id = iStrings[KStringPosition_Langid]->Word(2);
	const TPtrC8 id_des(reinterpret_cast<const TUint8*>(&id), sizeof(id));
	return Kern::ThreadDesWrite(aThread, &aLangId, id_des, 0);
	}


TInt TUsbcDescriptorPool::SetStringDescriptorLangId(TUint16 aLangId)
	{
	iStrings[KStringPosition_Langid]->SetWord(2, aLangId);
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetManufacturerStringDescriptorTC(DThread* aThread, TDes8& aString) const
	{
	return GetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Manufact,
									   KStringPosition_Manufact);
	}


TInt TUsbcDescriptorPool::SetManufacturerStringDescriptorTC(DThread* aThread, const TDes8& aString)
	{
	return SetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Manufact,
									   KStringPosition_Manufact);
	}


TInt TUsbcDescriptorPool::RemoveManufacturerStringDescriptor()
	{
	return RemoveDeviceStringDescriptor(KUsbDescStringIndex_Manufact, KStringPosition_Manufact);
	}


TInt TUsbcDescriptorPool::GetProductStringDescriptorTC(DThread* aThread, TDes8& aString) const
	{
	return GetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Product,
									   KStringPosition_Product);
	}


TInt TUsbcDescriptorPool::SetProductStringDescriptorTC(DThread* aThread, const TDes8& aString)
	{
	return SetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Product,
									   KStringPosition_Product);
	}


TInt TUsbcDescriptorPool::RemoveProductStringDescriptor()
	{
	return RemoveDeviceStringDescriptor(KUsbDescStringIndex_Product, KStringPosition_Product);
	}


TInt TUsbcDescriptorPool::GetSerialNumberStringDescriptorTC(DThread* aThread, TDes8& aString) const
	{
	return GetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Serial,
									   KStringPosition_Serial);
	}


TInt TUsbcDescriptorPool::SetSerialNumberStringDescriptorTC(DThread* aThread, const TDes8& aString)
	{
	return SetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Serial,
									   KStringPosition_Serial);
	}


TInt TUsbcDescriptorPool::RemoveSerialNumberStringDescriptor()
	{
	return RemoveDeviceStringDescriptor(KUsbDescStringIndex_Serial, KStringPosition_Serial);
	}


TInt TUsbcDescriptorPool::GetConfigurationStringDescriptorTC(DThread* aThread, TDes8& aString) const
	{
	const TInt str_idx = iDescriptors[KDescPosition_Config]->Byte(KUsbDescStringIndex_Config);
	if (str_idx)
		{
		__ASSERT_ALWAYS((str_idx == KStringPosition_Config), Kern::Fault(KUsbPanicCat, __LINE__));
		__KTRACE_OPT(KUSB, Kern::Printf("  String @ pos %d (conf $): \"%S\"",
										str_idx, &iStrings[str_idx]->StringData()));
		return Kern::ThreadDesWrite(aThread, &aString,
									iStrings[str_idx]->StringData(), 0);
		}
	else
		{
		__KTRACE_OPT(KUSB, Kern::Printf("  No config string descriptor @ pos %d", str_idx));
		return KErrNotFound;
		}
	}


TInt TUsbcDescriptorPool::SetConfigurationStringDescriptorTC(DThread* aThread, const TDes8& aString)
	{
	// we don't know the length of the string, so we have to allocate memory dynamically
	TUint strlen = Kern::ThreadGetDesLength(aThread, &aString);
	if (strlen > KUsbStringDescStringMaxSize)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: config $ descriptor too long - will be truncated"));
		strlen = KUsbStringDescStringMaxSize;
		}
	HBuf8* const strbuf = HBuf8::New(strlen);
	if (!strbuf)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Memory allocation for config $ desc string failed (1)"));
		return KErrNoMemory;
		}
	strbuf->SetMax();
	// the aString points to data that lives in user memory, so we have to copy it:
	const TInt r = Kern::ThreadDesRead(aThread, &aString, *strbuf, 0);
	if (r != KErrNone)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Thread read error"));
		delete strbuf;
		return r;
		}
	TUsbcStringDescriptor* sd = TUsbcStringDescriptor::New(*strbuf);
	if (!sd)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Memory allocation for config $ desc failed (2)"));
		delete strbuf;
		return KErrNoMemory;
		}
	// Delete old string, put in new one
	ExchangeStringDescriptor(KStringPosition_Config, sd);
	// Update Config descriptor string index field
	iDescriptors[KDescPosition_Config]->SetByte(KUsbDescStringIndex_Config, KStringPosition_Config);
	// Update Other_Speed_Config descriptor string index field as well, if applicable
	if (iDescriptors[KDescPosition_OtherSpeedConfig])
		iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(KUsbDescStringIndex_Config,
															  KStringPosition_Config);
	delete strbuf;
	return KErrNone;
	}


TInt TUsbcDescriptorPool::RemoveConfigurationStringDescriptor()
	{
	if (iDescriptors[KDescPosition_Config]->Byte(KUsbDescStringIndex_Config) == 0)
		{
		__KTRACE_OPT(KUSB, Kern::Printf("  RemoveConfigurationStringDescriptor: no $ desc @ index %d",
										KUsbDescStringIndex_Config));
		return KErrNotFound;
		}
	// Delete old string, put in NULL pointer
	ExchangeStringDescriptor(KStringPosition_Config, NULL);
	// Update Config descriptor string index field
	iDescriptors[KDescPosition_Config]->SetByte(KUsbDescStringIndex_Config, 0);
	// Update Other_Speed_Config descriptor string index field as well, if applicable
	if (iDescriptors[KDescPosition_OtherSpeedConfig])
		iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(KUsbDescStringIndex_Config, 0);
	return KErrNone;
	}


TInt TUsbcDescriptorPool::GetStringDescriptorTC(DThread* aThread, TInt aIndex, TDes8& aString) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetStringDescriptorTC()"));
	if (!StringDescriptorExists(aIndex))
		{
		return KErrNotFound;
		}
	__KTRACE_OPT(KUSB, Kern::Printf("  String @ pos %d: \"%S\"",
									aIndex, &iStrings[aIndex]->StringData()));
	return Kern::ThreadDesWrite(aThread, &aString, iStrings[aIndex]->StringData(), 0);
	}


TInt TUsbcDescriptorPool::SetStringDescriptorTC(DThread* aThread, TInt aIndex, const TDes8& aString)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetStringDescriptorTC()"));
	// we don't know the length of the string, so we have to allocate memory dynamically
	TUint strlen = Kern::ThreadGetDesLength(aThread, &aString);
	if (strlen > KUsbStringDescStringMaxSize)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: $ descriptor too long - will be truncated"));
		strlen = KUsbStringDescStringMaxSize;
		}
	HBuf8* strbuf = HBuf8::New(strlen);
	if (!strbuf)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Mem alloc for $ desc string failed (1)"));
		return KErrNoMemory;
		}
	strbuf->SetMax();
	// the aString points to data that lives in user memory, so we have to copy it over:
	const TInt r = Kern::ThreadDesRead(aThread, &aString, *strbuf, 0);
	if (r != KErrNone)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Thread read error"));
		delete strbuf;
		return r;
		}
	TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*strbuf);
	if (!sd)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Mem alloc for $ desc failed (2)"));
		delete strbuf;
		return KErrNoMemory;
		}
	if (aIndex < iStrings.Count())
		{
		ExchangeStringDescriptor(aIndex, sd);
		}
	else // if (aIndex >= iStrings.Count())
		{
		while (aIndex > iStrings.Count())
			{
			iStrings.Append(NULL);
			}
		iStrings.Append(sd);
		}
	delete strbuf;
	return KErrNone;
	}


TInt TUsbcDescriptorPool::RemoveStringDescriptor(TInt aIndex)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::RemoveStringDescriptor()"));
	if (!StringDescriptorExists(aIndex))
		{
		return KErrNotFound;
		}
	__KTRACE_OPT(KUSB, Kern::Printf("  Removing string @ pos %d: \"%S\"",
									aIndex, &iStrings[aIndex]->StringData()));
	ExchangeStringDescriptor(aIndex, NULL);

	// Make sure there's no $ after aIndex.
	const TInt n = iStrings.Count();
	for (TInt i = aIndex; i < n; i++)
		{
		if (iStrings[i] != NULL)
			{
			__KTRACE_OPT(KUSB, Kern::Printf("  Found $ @ idx %d - not compressing", i));
			return KErrNone;
			}
		}

	__KTRACE_OPT(KUSB, Kern::Printf("  No $ found after idx %d - compressing array", aIndex));
	// Move aIndex back just before the first !NULL element.
	while (iStrings[--aIndex] == NULL)
		;
	// Let aIndex point to first NULL.
	aIndex++;
	__KTRACE_OPT(KUSB, Kern::Printf("  Starting at index %d", aIndex));
	// Now remove NULL pointers until (Count() == aIndex).
	__KTRACE_OPT(KUSB, Kern::Printf("  iStrings.Count() before: %d", iStrings.Count()));
	do
		{
		iStrings.Remove(aIndex);
		__KTRACE_OPT(KUSB, Kern::Printf("  Removing $"));
		}
	while (iStrings.Count() > aIndex);
	__KTRACE_OPT(KUSB, Kern::Printf("  iStrings.Count() after: %d", iStrings.Count()));

	// Regain some memory.
	iStrings.Compress();

	return KErrNone;
	}


// ===================================================================
// --- private ---
// ===================================================================

//
// Insert an Interface descriptor into the descriptor array at the appropriate index.
//
void TUsbcDescriptorPool::InsertIfcDesc(TUsbcDescriptorBase* aDesc)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InsertIfcDesc()"));

	const TInt count = iDescriptors.Count();
	TBool ifc_exists = EFalse;								// set to 'true' if we're adding an alternate
															// setting to an already existing interface
	TInt i = KDescPosition_FirstAvailable;
	while (i < count)
		{
		__KTRACE_OPT(KUSB, Kern::Printf("  already descriptors there (%d)...", count));
		if (iDescriptors[i]->Type() == KUsbDescType_Interface)
			{
			if (iDescriptors[i]->Byte(2) > aDesc->Byte(2))
				{
				// our interface number is less than the one's just found => insert before it (= here)
				break;
				}
			else if (iDescriptors[i]->Byte(2) == aDesc->Byte(2))
				{
				ifc_exists = ETrue;
				// same interface number => look at settings number
				if (iDescriptors[i]->Byte(3) > aDesc->Byte(3))
					{
					// our setting number is less than the one's found => insert before (= here)
					break;
					}
				else if (iDescriptors[i]->Byte(3) == aDesc->Byte(3))
					{
					__KTRACE_OPT(KPANIC, Kern::Printf("  Error: first delete old desc "
													  "(TUsbcDescriptorPool::InsertIfcDesc)"));
					return;
					}
				}
			}
		++i;
		}
	// In any case: put the new descriptor at position i.
	__KTRACE_OPT(KUSB, Kern::Printf("  inserting descriptor at position %d", i));
	iDescriptors.Insert(aDesc, i);

	// Update the config descriptor's wTotalLength field.
	UpdateConfigDescriptorLength(KUsbDescSize_Interface);

	if (!ifc_exists)
		{
		// If this is the first setting for the interface, increment bNumInterfaces.
		UpdateConfigDescriptorNumIfcs(1);
		}

	iIfcIdx = i;
	}


//
// Insert an Endpoint descriptor into the descriptor array at the appropriate index.
//
void TUsbcDescriptorPool::InsertEpDesc(TUsbcDescriptorBase* aDesc)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InsertEpDesc()"));
	if (iIfcIdx == 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: only after interface "
										  "(TUsbcDescriptorPool::InsertEpDesc)"));
		return;
		}
	const TInt count = iDescriptors.Count();
	TInt i = iIfcIdx + 1;
	while (i < count)
		{
		if (iDescriptors[i]->Type() != KUsbDescType_Endpoint)
			break;
		++i;
		}
	// put the new descriptor at position i
	iDescriptors.Insert(aDesc, i);
	// update the config descriptor's wTotalLength field
	UpdateConfigDescriptorLength(aDesc->Size());
	}


//
// Find the index of the Interface descriptor for a given interface setting.
//
TInt TUsbcDescriptorPool::FindIfcDescriptor(TInt aIfcNumber, TInt aIfcSetting) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindIfcDescriptor(%d, %d)",
									aIfcNumber, aIfcSetting));
	const TInt count = iDescriptors.Count();
	for (TInt i = KDescPosition_FirstAvailable; i < count; i++)
		{
		if ((iDescriptors[i]->Type() == KUsbDescType_Interface) &&
			(iDescriptors[i]->Byte(2) == aIfcNumber) &&
			(iDescriptors[i]->Byte(3) == aIfcSetting))
			{
			return i;
			}
		}
	__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
	return -1;
	}


//
// Find the index of the Endpoint descriptor for a given endpoint on a given interface setting.
//
TInt TUsbcDescriptorPool::FindEpDescriptor(TInt aIfcNumber, TInt aIfcSetting, TUint8 aEpAddress) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindEpDescriptor(%d, %d, 0x%02x)",
									aIfcNumber, aIfcSetting, aEpAddress));
	// first find the interface
	const TInt ifc = FindIfcDescriptor(aIfcNumber, aIfcSetting);
	if (ifc < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such interface"));
		return ifc;
		}
	const TInt count = iDescriptors.Count();
	// then, before the next interface, try to locate the endpoint
	for (TInt i = ifc + 1; i < count; i++)
		{
		if (iDescriptors[i]->Type() == KUsbDescType_Interface)
			{
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint before next interface"));
			return -1;
			}
		else if ((iDescriptors[i]->Type() == KUsbDescType_Endpoint) &&
				 (iDescriptors[i]->Byte(2) == aEpAddress))
			{
			// found
			return i;
			}
		}
	__KTRACE_OPT(KPANIC, Kern::Printf("  Error: no such endpoint"));
	return -1;
	}


//
// Delete n descriptors starting from aIndex and remove their pointers from the array.
//
void TUsbcDescriptorPool::DeleteDescriptors(TInt aIndex, TInt aCount)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::DeleteDescriptors()"));
	if (aIndex < KDescPosition_FirstAvailable)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: aIndex < KDescPosition_FirstAvailable"));
		return;
		}
	if (aCount <= 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: aCount <= 0"));
		return;
		}
	__KTRACE_OPT(KUSB, Kern::Printf("  Removing descriptors at index %d:", aIndex));
	// Try to update wTotalLength field in Config descriptor
	while (aCount--)
		{
		// In this loop we don't decrement aIndex, because after deleting an element
		// aIndex is already indexing the next one.
		TUsbcDescriptorBase* const ptr = iDescriptors[aIndex];
		switch (ptr->Type())
			{
		case KUsbDescType_Interface:
			__KTRACE_OPT(KUSB, Kern::Printf("  - an interface descriptor"));
			UpdateConfigDescriptorLength(-KUsbDescSize_Interface);
			break;
		case KUsbDescType_Endpoint:
			__KTRACE_OPT(KUSB, Kern::Printf("  - an endpoint descriptor"));
			UpdateConfigDescriptorLength(-ptr->Size());
			break;
		case KUsbDescType_CS_Interface:
			/* fall through */
		case KUsbDescType_CS_Endpoint:
			__KTRACE_OPT(KUSB, Kern::Printf("  - a class specific descriptor"));
			UpdateConfigDescriptorLength(-ptr->Size());
			break;
		default:
			__KTRACE_OPT(KUSB, Kern::Printf("  - an unknown descriptor"));
			__KTRACE_OPT(KPANIC, Kern::Printf("  Error: unknown descriptor type"));
			}
		iDescriptors.Remove(aIndex);
		delete ptr;
		}
	}


//
// Update the wTotalLength field in the Configuration descriptor (aLength can be negative).
//
void TUsbcDescriptorPool::UpdateConfigDescriptorLength(TInt aLength)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateConfigDescriptorLength(%d)", aLength));
	TUsbcDescriptorBase* const cnf = iDescriptors[KDescPosition_Config];
	__KTRACE_OPT(KUSB, Kern::Printf("  wTotalLength old: %d", cnf->Word(2)));
	// Update Config descriptor
	cnf->SetWord(2, cnf->Word(2) + aLength);
	__KTRACE_OPT(KUSB, Kern::Printf("  wTotalLength new: %d", cnf->Word(2)));
	// Update Other_Speed_Config descriptor as well, if applicable
	if (iDescriptors[KDescPosition_OtherSpeedConfig])
		iDescriptors[KDescPosition_OtherSpeedConfig]->SetWord(2, cnf->Word(2));
	}


//
// Update the bNumInterfaces field in the Configuration descriptor (aNumber can be negative).
//
void TUsbcDescriptorPool::UpdateConfigDescriptorNumIfcs(TInt aNumber)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateConfigDescriptorNumIfcs(%d)", aNumber));
	TUsbcDescriptorBase* const cnf = iDescriptors[KDescPosition_Config];
	__KTRACE_OPT(KUSB, Kern::Printf("  bNumInterfaces old: %d", cnf->Byte(4)));
	const TInt n = cnf->Byte(4) + aNumber;
	if (n < 0)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: bNumInterfaces + aNumber < 0"));
		return;
		}
	// Update Config descriptor
	cnf->SetByte(4, n);
	__KTRACE_OPT(KUSB, Kern::Printf("  bNumInterfaces new: %d", cnf->Byte(4)));
	// Update Other_Speed_Config descriptor as well, if applicable
	if (iDescriptors[KDescPosition_OtherSpeedConfig])
		iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(4, n);
	}


//
// Update the bNumInterfaces field in the Configuration descriptor if necessary.
//
void TUsbcDescriptorPool::UpdateIfcNumbers(TInt aNumber)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateIfcNumbers(%d)", aNumber));
	const TInt count = iDescriptors.Count();
	for (TInt i = KDescPosition_FirstAvailable; i < count; i++)
		{
		if ((iDescriptors[i]->Type() == KUsbDescType_Interface) &&
			(iDescriptors[i]->Byte(2) == aNumber))
			{
			// there's still an interface with 'number' so we don't need to update anything
			return;
			}
		}
	// if we haven't returned yet, we decrement bNumInterfaces
	UpdateConfigDescriptorNumIfcs(-1);
	}


//
// Put the current Device or Device_Qualifier descriptor in the Ep0 Tx buffer.
// Only used for Ep0 standard requests, so target buffer can be hard-wired.
//
TInt TUsbcDescriptorPool::GetDeviceDescriptor(TInt aIndex) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceDescriptor()"));
	__ASSERT_DEBUG((aIndex == KDescPosition_Device) || (aIndex == KDescPosition_DeviceQualifier),
				   Kern::Printf("  Error: invalid descriptor index: %d", aIndex));
	if (iDescriptors[aIndex] == NULL)
		{
		// This doesn't have to be an error - we might get asked here for the Device_Qualifier descriptor
		// on a FS-only device.
		__KTRACE_OPT(KUSB, Kern::Printf("  Descriptor #%d requested but not available", aIndex));
		return 0;
		}
	return iDescriptors[aIndex]->GetDescriptorData(iEp0_TxBuf, KUsbcBufSz_Ep0Tx);
	}


//
// Put the current Configuration or Other_Speed_Configuration descriptor + all the following
// descriptors in the Ep0 Tx buffer.
// Only used for Ep0 standard requests, so target buffer can be hard-wired.
//
TInt TUsbcDescriptorPool::GetConfigurationDescriptor(TInt aIndex) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetConfigDescriptor(%d)", aIndex));
	__ASSERT_DEBUG((aIndex == KDescPosition_Config) || (aIndex == KDescPosition_OtherSpeedConfig),
				   Kern::Printf("  Error: invalid descriptor index: %d", aIndex));
	if (iDescriptors[aIndex] == NULL)
		{
		// This is always an error: We should always have a Configuration descriptor and we should never
		// get asked for the Other_Speed_Configuration descriptor if we don't have one (9.6.2).
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: Descriptor %d requested but not available", aIndex));
		return 0;
		}
	const TInt count = iDescriptors.Count();
	TInt copied = 0;
	TUint8* buf = iEp0_TxBuf;
	for (TInt i = aIndex; i < count; i++)
		{
		TUsbcDescriptorBase* const ptr = iDescriptors[i];
		if ((aIndex == KDescPosition_OtherSpeedConfig) && (i == KDescPosition_Config))
			{
			// Skip Config descriptor when returning Other_Speed_Config
			continue;
			}
		if ((i == KDescPosition_Otg) && (iDescriptors[i] == NULL))
			{
			__KTRACE_OPT(KUSB, Kern::Printf("  no OTG descriptor -> next"));
			continue;
			}
		// We need to edit endpoint descriptors on the fly because we have only one copy
		// of each and that copy has to contain different information, depending on the
		// current speed and the type of descriptor requested.
		if (ptr->Type() == KUsbDescType_Endpoint)
			{
			if ((iHighSpeed && (aIndex == KDescPosition_Config)) ||
				(!iHighSpeed && (aIndex == KDescPosition_OtherSpeedConfig)))
				{
				ptr->UpdateHs();
				}
			else
				{
				ptr->UpdateFs();
				}
			}
		__KTRACE_OPT(KUSB, Kern::Printf("  desc[%02d]: type = 0x%02x size = %d ",
										i, ptr->Type(), ptr->Size()));
		const TInt size = ptr->GetDescriptorData(buf, KUsbcBufSz_Ep0Tx - copied);
		if (size == 0)
			{
			__KTRACE_OPT(KPANIC,
						 Kern::Printf("  Error: No Tx buffer space to copy this descriptor -> exiting"));
			break;
			}
		copied += size;
		if (copied >= KUsbcBufSz_Ep0Tx)
			{
			__KTRACE_OPT(KPANIC,
						 Kern::Printf("  Error: No Tx buffer space left -> stopping here"));
			break;
			}
		buf += size;
		}
	__KTRACE_OPT(KUSB, Kern::Printf("  copied %d bytes", copied));
	return copied;
	}


//
// Put the current OTG descriptor in the Ep0 Tx buffer.
// Only used for Ep0 standard requests, so target buffer can be hard-wired.
//
TInt TUsbcDescriptorPool::GetOtgDescriptor() const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetOtgDescriptor()"));
	if (iDescriptors[KDescPosition_Otg] == NULL)
		{
		__KTRACE_OPT(KUSB, Kern::Printf("  OTG Descriptor not set"));
		return 0;
		}
	return iDescriptors[KDescPosition_Otg]->GetDescriptorData(iEp0_TxBuf, KUsbcBufSz_Ep0Tx);
	}


//
// Put a specific String descriptor in the Ep0 Tx buffer.
// Only used for Ep0 standard requests, so target buffer can be hard-wired.
//
TInt TUsbcDescriptorPool::GetStringDescriptor(TInt aIndex) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetStringDescriptor(%d)", aIndex));
	// I really would have liked to display the descriptor contents here, but without trailing zero
	// we got a problem: how can we tell printf where the string ends? We would have to
	// dynamically allocate memory (since we don't know the size in advance), copy the descriptor
	// contents there, append a zero, and give this to printf. That's a bit too much effort...
	if (!StringDescriptorExists(aIndex))
		{
		return 0;
		}
	return iStrings[aIndex]->GetDescriptorData(iEp0_TxBuf, KUsbcBufSz_Ep0Tx);
	}


//
// Write a String descriptor pointed to by the Device descriptor to the user side
// (one of Manufacturer, Product, SerialNumber).
//
TInt TUsbcDescriptorPool::GetDeviceStringDescriptorTC(DThread* aThread, TDes8& aString,
													  TInt aIndex, TInt aPosition) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceStringDescriptorTC()"));
	const TInt str_idx = iDescriptors[KDescPosition_Device]->Byte(aIndex);
	if (str_idx)
		{
		__ASSERT_ALWAYS((str_idx == aPosition), Kern::Fault(KUsbPanicCat, __LINE__));
		__KTRACE_OPT(KUSB, Kern::Printf("  String @ pos %d (device $): \"%S\"",
										str_idx, &iStrings[str_idx]->StringData()));
		return Kern::ThreadDesWrite(aThread, &aString,
									iStrings[str_idx]->StringData(), 0);
		}
	else
		{
		__KTRACE_OPT(KUSB, Kern::Printf("  No string descriptor @ pos %d", aIndex));
		return KErrNotFound;
		}
	}


//
// Read a Device String descriptor from the user side and put in the descriptor arrays
// (one of Manufacturer, Product, SerialNumber).
//
TInt TUsbcDescriptorPool::SetDeviceStringDescriptorTC(DThread* aThread, const TDes8& aString,
													  TInt aIndex, TInt aPosition)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetDeviceStringDescriptorTC()"));
	// we don't know the length of the string, so we have to allocate memory dynamically
	TUint strlen = Kern::ThreadGetDesLength(aThread, &aString);
	if (strlen > KUsbStringDescStringMaxSize)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Warning: $ descriptor too long - will be truncated"));
		strlen = KUsbStringDescStringMaxSize;
		}
	HBuf8* const strbuf = HBuf8::New(strlen);
	if (!strbuf)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Memory allocation for dev $ desc string failed (1)"));
		return KErrNoMemory;
		}
	strbuf->SetMax();
	// the aString points to data that lives in user memory, so we have to copy it:
	const TInt r = Kern::ThreadDesRead(aThread, &aString, *strbuf, 0);
	if (r != KErrNone)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Thread read error"));
		delete strbuf;
		return r;
		}
	TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*strbuf);
	if (!sd)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Memory allocation for dev $ desc failed (2)"));
		delete strbuf;
		return KErrNoMemory;
		}
	ExchangeStringDescriptor(aPosition, sd);
	iDescriptors[KDescPosition_Device]->SetByte(aIndex, aPosition);
	delete strbuf;
	return r;
	}


//
// Remove a Device String descriptor from the descriptor arrays
// (one of Manufacturer, Product, SerialNumber).
//
TInt TUsbcDescriptorPool::RemoveDeviceStringDescriptor(TInt aIndex, TInt aPosition)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::RemoveDeviceStringDescriptor()"));
	if (iDescriptors[KDescPosition_Device]->Byte(aIndex) == 0)
		{
		__KTRACE_OPT(KUSB, Kern::Printf("  RemoveDeviceStringDescriptor: no $ desc @ index %d", aIndex));
		return KErrNotFound;
		}
	ExchangeStringDescriptor(aPosition, NULL);
	iDescriptors[KDescPosition_Device]->SetByte(aIndex, 0);
	return KErrNone;
	}


//
// Puts aDesc at postion aIndex in the string descriptor array, after deleting what was (possibly) there.
//
void TUsbcDescriptorPool::ExchangeStringDescriptor(TInt aIndex, const TUsbcStringDescriptor* aDesc)
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::ExchangeStringDescriptor()"));
	TUsbcStringDescriptorBase* const ptr = iStrings[aIndex];
	__KTRACE_OPT(KUSB, Kern::Printf("  Deleting string descriptor at index %d: 0x%x", aIndex, ptr));
	iStrings.Remove(aIndex);
	delete ptr;
	__KTRACE_OPT(KUSB, Kern::Printf("  Inserting string descriptor at index %d: 0x%x", aIndex, aDesc));
	iStrings.Insert(aDesc, aIndex);
	}


//
// Checks whether there are any string descriptors in the array (apart from LangID).
//
TBool TUsbcDescriptorPool::AnyStringDescriptors() const
	{
	const TInt n = iStrings.Count();
	for (TInt i = 1; i < n; i++)
		{
		if (iStrings[i] != NULL)
			return ETrue;
		}
	return EFalse;
	}


//
// Returns true if aIndex exists and what is at that positition is not a NULL pointer.
//
TBool TUsbcDescriptorPool::StringDescriptorExists(TInt aIndex) const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::StringDescriptorExists()"));
	if (aIndex >= iStrings.Count())
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: Bad string index: %d", aIndex));
		return EFalse;
		}
	else if (iStrings[aIndex] == NULL)
		{
		__KTRACE_OPT(KPANIC, Kern::Printf("  Error: No $ descriptor @ pos %d", aIndex));
		return EFalse;
		}
	return ETrue;
	}


//
//
//
TInt TUsbcDescriptorPool::FindAvailableStringPos() const
	{
	__KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindAvailableStringPos()"));
	const TInt n = iStrings.Count();
	// We don't start from 0 because the first few locations are 'reserved'.
	for (TInt i = KStringPosition_FirstAvailable; i < n; i++)
		{
		if (iStrings[i] == NULL)
			{
			__KTRACE_OPT(KUSB, Kern::Printf(" Found available NULL position: %d", i));
			return i;
			}
		}
	return -1;
	}


// -eof-