kernel/eka/drivers/usbcc/descriptors.cpp
changeset 0 a41df078684a
child 24 41f0cfe18c80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbcc/descriptors.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2361 @@
+// 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-