kerneltest/e32test/usb/t_usb_device/src/apitests.cpp
changeset 0 a41df078684a
child 253 d37db4dcc88d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/usb/t_usb_device/src/apitests.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1005 @@
+// 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:
+// e32test/usb/t_usb_device/src/apitests.cpp
+// USB Test Program T_USB_DEVICE, functional part.
+// Device-side part, to work against T_USB_HOST running on the host.
+// 
+//
+
+#include "general.h"									// CActiveControl, CActiveRW
+#include "config.h"
+#include "usblib.h"										// Helpers
+
+extern RTest test;
+extern TBool gVerbose;
+extern TBool gSkip;
+extern TBool gTempTest;
+
+_LIT16(KString_one, "Arbitrary String Descriptor Test String 1");
+_LIT16(KString_two, "Another Arbitrary String Descriptor Test String");
+
+void SetupDescriptors(LDDConfigPtr aLddPtr,RDEVCLIENT* aPort, TUint16 aPid = 0)
+	{
+	// === Device Descriptor
+	test.Start(_L("Set up descriptors"));
+
+	test.Next(_L("GetDeviceDescriptorSize"));
+	TInt deviceDescriptorSize = 0;
+	aPort->GetDeviceDescriptorSize(deviceDescriptorSize);
+	test_Equal(KUsbDescSize_Device,static_cast<TUint>(deviceDescriptorSize));
+
+	test.Next(_L("GetDeviceDescriptor"));
+	TBuf8<KUsbDescSize_Device> deviceDescriptor;
+	TInt r = aPort->GetDeviceDescriptor(deviceDescriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("SetDeviceDescriptor"));
+	const TInt KUsbSpecOffset = 2;
+	const TInt KUsbDevClass = 4;
+	const TInt KUsbDevSubClass = 5;
+	const TInt KUsbDevProtocol = 6;
+	const TInt KUsbVendorIdOffset = 8;
+	const TInt KUsbProductIdOffset = 10;
+	const TInt KUsbDevReleaseOffset = 12;
+	// Change the USB spec number
+	deviceDescriptor[KUsbSpecOffset]   = LoByte(aLddPtr->iSpec);
+	deviceDescriptor[KUsbSpecOffset+1] = HiByte(aLddPtr->iSpec);
+	// Change the Device Class, SubClass and Protocol to zero so that they are not device specific
+	// and diferent clases can used on different interfaces
+	deviceDescriptor[KUsbDevClass] = 0;
+	deviceDescriptor[KUsbDevSubClass] = 0;
+	deviceDescriptor[KUsbDevProtocol] = 0;
+	// Change the device vendor ID (VID)
+	deviceDescriptor[KUsbVendorIdOffset]   = LoByte(aLddPtr->iVid);			// little endian!
+	deviceDescriptor[KUsbVendorIdOffset+1] = HiByte(aLddPtr->iVid);
+	// Change the device product ID (PID)
+	if (aPid != 0)
+		{	
+		deviceDescriptor[KUsbProductIdOffset]	= LoByte(aPid);		// little endian!
+		deviceDescriptor[KUsbProductIdOffset+1] = HiByte(aPid);		
+		}
+	else
+		{
+		deviceDescriptor[KUsbProductIdOffset]	= LoByte(aLddPtr->iPid);		// little endian!
+		deviceDescriptor[KUsbProductIdOffset+1] = HiByte(aLddPtr->iPid);		
+		}
+	// Change the device release number
+	deviceDescriptor[KUsbDevReleaseOffset]	 = LoByte(aLddPtr->iRelease);	// little endian!
+	deviceDescriptor[KUsbDevReleaseOffset+1] = HiByte(aLddPtr->iRelease);
+	r = aPort->SetDeviceDescriptor(deviceDescriptor);
+	test_KErrNone(r);
+
+	if (!gSkip)
+		{
+		test.Next(_L("GetDeviceDescriptor()"));
+		TBuf8<KUsbDescSize_Device> descriptor2;
+		r = aPort->GetDeviceDescriptor(descriptor2);
+		test_KErrNone(r);
+
+		test.Next(_L("Compare device descriptor with value set"));
+		r = descriptor2.Compare(deviceDescriptor);
+		test_KErrNone(r);	
+		}
+
+	// === Configuration Descriptor
+
+	test.Next(_L("GetConfigurationDescriptorSize"));
+	TInt configDescriptorSize = 0;
+	aPort->GetConfigurationDescriptorSize(configDescriptorSize);
+	test_Equal(KUsbDescSize_Config,static_cast<TUint>(configDescriptorSize));
+
+	test.Next(_L("GetConfigurationDescriptor"));
+	TBuf8<KUsbDescSize_Config> configDescriptor;
+	r = aPort->GetConfigurationDescriptor(configDescriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("SetConfigurationDescriptor"));
+	// Change Self Power and Remote Wakeup
+	const TInt KUsbAttributesOffset = 7;
+	const TUint8 KUsbAttributeDefault = 0x80;
+	const TUint8 KUsbAttributeSelfPower = 0x40;
+	const TUint8 KUsbAttributeRemoteWakeup = 0x20;
+	configDescriptor[KUsbAttributesOffset] = KUsbAttributeDefault | (aLddPtr->iSelfPower ? KUsbAttributeSelfPower : 0) 
+													| (aLddPtr->iRemoteWakeup ? KUsbAttributeRemoteWakeup : 0);
+	// Change the reported max power
+	// 100mA (= 2 * 0x32) is the highest value allowed for a bus-powered device.
+	const TInt KUsbMaxPowerOffset = 8;
+	configDescriptor[KUsbMaxPowerOffset] = aLddPtr->iMaxPower;
+	r = aPort->SetConfigurationDescriptor(configDescriptor);
+	test_KErrNone(r);
+
+	if (!gSkip)
+		{
+		test.Next(_L("GetConfigurationDescriptor()"));
+		TBuf8<KUsbDescSize_Config> descriptor2;
+		r = aPort->GetConfigurationDescriptor(descriptor2);
+		test_KErrNone(r);
+
+		test.Next(_L("Compare configuration desc with value set"));
+		r = descriptor2.Compare(configDescriptor);
+		test_KErrNone(r);
+		}
+		
+	// === String Descriptors
+
+	test.Next(_L("SetStringDescriptor"));
+
+	// Set up any standard string descriptors that were defined in the xml config
+	if (aLddPtr->iManufacturer)
+		{
+		r = aPort->SetManufacturerStringDescriptor(* aLddPtr->iManufacturer);
+		test_KErrNone(r);
+		}
+		
+	if (aLddPtr->iProduct)
+		{
+		r = aPort->SetProductStringDescriptor(* aLddPtr->iProduct);
+		test_KErrNone(r);
+		}
+
+	if (aLddPtr->iSerialNumber)
+		{
+		r = aPort->SetSerialNumberStringDescriptor(* aLddPtr->iSerialNumber);
+		test_KErrNone(r);
+		}
+
+	// Set up two arbitrary string descriptors, which can be queried
+	// manually from the host side for testing purposes
+	
+	TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(KString_one);
+	r = aPort->SetStringDescriptor(stridx1, wr_str);
+	test_KErrNone(r);
+
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = KString_two;
+	r = aPort->SetStringDescriptor(stridx2, wr_str);
+	test_KErrNone(r);
+
+	test.End();
+	
+	}
+
+static void TestDeviceQualifierDescriptor(RDEVCLIENT* aPort)
+	{
+	test.Start(_L("Device_Qualifier Descriptor Manipulation"));
+
+	test.Next(_L("GetDeviceQualifierDescriptor()"));
+	TBuf8<KUsbDescSize_DeviceQualifier> descriptor;
+	TInt r = aPort->GetDeviceQualifierDescriptor(descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("SetDeviceQualifierDescriptor()"));
+	// Change the USB spec number to 3.00
+	descriptor[KDevDesc_SpecOffset]   = 0x00;
+	descriptor[KDevDesc_SpecOffset+1] = 0x03;
+	// Change the device class, subclass and protocol codes
+	descriptor[KDevDesc_DevClassOffset]    = 0xA1;
+	descriptor[KDevDesc_DevSubClassOffset] = 0xB2;
+	descriptor[KDevDesc_DevProtocolOffset] = 0xC3;
+	r = aPort->SetDeviceQualifierDescriptor(descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("GetDeviceQualifierDescriptor()"));
+	TBuf8<KUsbDescSize_DeviceQualifier> descriptor2;
+	r = aPort->GetDeviceQualifierDescriptor(descriptor2);
+	test_KErrNone(r);
+
+	test.Next(_L("Compare Device_Qualifier desc with value set"));
+	r = descriptor2.Compare(descriptor);
+	test_Equal(0,r);
+
+	test.End();
+	}
+
+
+
+static void	TestOtherSpeedConfigurationDescriptor(RDEVCLIENT* aPort)
+	{
+	test.Start(_L("Other_Speed_Configuration Desc Manipulation"));
+
+	test.Next(_L("GetOtherSpeedConfigurationDescriptor()"));
+	TBuf8<KUsbDescSize_OtherSpeedConfig> descriptor;
+	TInt r = aPort->GetOtherSpeedConfigurationDescriptor(descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("SetOtherSpeedConfigurationDescriptor()"));
+	// Invert Remote-Wakup support
+	descriptor[KConfDesc_AttribOffset] = (descriptor[KConfDesc_AttribOffset] ^ KUsbDevAttr_RemoteWakeup);
+	// Change the reported max power to 330mA (2 * 0xA5)
+	descriptor[KConfDesc_MaxPowerOffset] = 0xA5;
+	r = aPort->SetOtherSpeedConfigurationDescriptor(descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("GetOtherSpeedConfigurationDescriptor()"));
+	TBuf8<KUsbDescSize_OtherSpeedConfig> descriptor2;
+	r = aPort->GetOtherSpeedConfigurationDescriptor(descriptor2);
+	test_KErrNone(r);
+
+	test.Next(_L("Compare O_S_Config desc with value set"));
+	r = descriptor2.Compare(descriptor);
+	test_KErrNone(r);
+
+	test.End();
+	}
+
+
+static void TestInterfaceDescriptor(RDEVCLIENT* aPort, TInt aNumSettings)
+	{
+	test.Start(_L("Interface Descriptor Manipulation"));
+
+	// For all settings
+
+	TInt desc_size = 0;
+	TInt r = 0;
+	TBuf8<KUsbDescSize_Interface> descriptor;
+	TBuf8<KUsbDescSize_Interface> descriptor2;
+	for (TInt i =0; i < aNumSettings; i++)
+		{
+		
+		test.Next(_L("GetInterfaceDescriptorSize()"));
+		r = aPort->GetInterfaceDescriptorSize(i, desc_size);
+		if (r != KErrNone)
+			{
+			RDebug::Printf ("Error %d in GetInterfaceDescriptorSize %d\n",r,i);
+			}
+		test_KErrNone(r);
+		test_Equal(KUsbDescSize_Interface,static_cast<TUint>(desc_size));
+
+		test.Next(_L("GetInterfaceDescriptor()"));
+		r = aPort->GetInterfaceDescriptor(i, descriptor);
+		test_KErrNone(r);
+
+		test.Next(_L("SetInterfaceDescriptor()"));
+		// Change the interface protocol to 0x78(+)
+		TUint8 prot = 0x78;
+		if (descriptor[KIfcDesc_ProtocolOffset] == prot)
+			prot++;
+		descriptor[KIfcDesc_ProtocolOffset] = prot;
+		r = aPort->SetInterfaceDescriptor(i, descriptor);
+		test_KErrNone(r);
+
+		test.Next(_L("GetInterfaceDescriptor()"));
+		r = aPort->GetInterfaceDescriptor(i, descriptor2);
+		test_KErrNone(r);
+
+		test.Next(_L("Compare interface descriptor with value set"));
+		r = descriptor2.Compare(descriptor);
+		test_KErrNone(r);
+		}
+		
+	test.Next(_L("GetInterfaceDescriptor()"));
+	r = aPort->GetInterfaceDescriptor(aNumSettings, descriptor);
+	test_Equal(KErrNotFound,r);
+
+	test.Next(_L("SetInterfaceDescriptor()"));
+	r = aPort->SetInterfaceDescriptor(aNumSettings, descriptor);
+	test_Equal(KErrNotFound,r);
+		
+	test.End();
+	}
+
+
+static void TestClassSpecificDescriptors(RDEVCLIENT* aPort)
+	{
+	test.Start(_L("Class-specific Descriptor Manipulation"));
+
+	// First a class-specific Interface descriptor
+
+	test.Next(_L("SetCSInterfaceDescriptorBlock()"));
+	// choose arbitrary new descriptor size
+	const TInt KUsbDescSize_CS_Interface = KUsbDescSize_Interface + 10;
+	TBuf8<KUsbDescSize_CS_Interface> cs_ifc_descriptor;
+	cs_ifc_descriptor.FillZ(cs_ifc_descriptor.MaxLength());
+	cs_ifc_descriptor[KUsbDesc_SizeOffset] = KUsbDescSize_CS_Interface;
+	cs_ifc_descriptor[KUsbDesc_TypeOffset] = KUsbDescType_CS_Interface;
+	TInt r = aPort->SetCSInterfaceDescriptorBlock(0, cs_ifc_descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("GetCSInterfaceDescriptorBlockSize()"));
+	TInt desc_size = 0;
+	r = aPort->GetCSInterfaceDescriptorBlockSize(0, desc_size);
+	test_KErrNone(r);
+	test_Equal(KUsbDescSize_CS_Interface,desc_size);
+
+	test.Next(_L("GetCSInterfaceDescriptorBlock()"));
+	TBuf8<KUsbDescSize_CS_Interface> descriptor;
+	r = aPort->GetCSInterfaceDescriptorBlock(0, descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("Compare CS ifc descriptor with value set"));
+	r = descriptor.Compare(cs_ifc_descriptor);
+	test_KErrNone(r);
+
+	// Next a class-specific Endpoint descriptor
+
+	test.Next(_L("SetCSEndpointDescriptorBlock()"));
+	// choose arbitrary new descriptor size
+	const TInt KUsbDescSize_CS_Endpoint = KUsbDescSize_Endpoint + 5;
+	TBuf8<KUsbDescSize_CS_Endpoint> cs_ep_descriptor;
+	cs_ep_descriptor.FillZ(cs_ep_descriptor.MaxLength());
+	cs_ep_descriptor[KUsbDesc_SizeOffset] = KUsbDescSize_CS_Endpoint;
+	cs_ep_descriptor[KUsbDesc_TypeOffset] = KUsbDescType_CS_Endpoint;
+	r = aPort->SetCSEndpointDescriptorBlock(0, 2, cs_ep_descriptor);
+	test_KErrNone(r);
+
+	test.Next(_L("GetCSEndpointDescriptorBlockSize()"));
+	r = aPort->GetCSEndpointDescriptorBlockSize(0, 2, desc_size);
+	test_KErrNone(r);
+	test_Equal(KUsbDescSize_CS_Endpoint,desc_size);
+
+	test.Next(_L("GetCSEndpointDescriptorBlock()"));
+	TBuf8<KUsbDescSize_CS_Endpoint> descriptor2;
+	r = aPort->GetCSEndpointDescriptorBlock(0, 2, descriptor2);
+	test_KErrNone(r);
+
+	test.Next(_L("Compare CS ep descriptor with value set"));
+	r = descriptor2.Compare(cs_ep_descriptor);
+	test_KErrNone(r);
+
+	test.End();
+	}
+
+
+void TestEndpointDescriptor(RDEVCLIENT* aPort,TInt aIfSetting, TInt aEpNumber,TUsbcEndpointInfo aEpInfo)
+	{
+	test.Start(_L("Endpoint Descriptor Manipulation"));
+
+	TBuf8<KUsbDescSize_AudioEndpoint> epDescriptor;
+	TInt desc_size;
+	TInt r = aPort->GetEndpointDescriptorSize(aIfSetting, aEpNumber, desc_size);
+	test_KErrNone(r);
+	test_Equal(KUsbDescSize_Endpoint + aEpInfo.iExtra,static_cast<TUint>(desc_size));
+
+	r = aPort->GetEndpointDescriptor(aIfSetting, aEpNumber, epDescriptor);
+	test_KErrNone(r);
+
+	test(((aEpInfo.iDir & KUsbEpDirIn) && (epDescriptor[KEpDesc_AddressOffset] & 0x80) ||
+		!(aEpInfo.iDir & KUsbEpDirIn) && !(epDescriptor[KEpDesc_AddressOffset] & 0x80)) &&
+			EpTypeMask2Value(aEpInfo.iType) == (TUint)(epDescriptor[KEpDesc_AttributesOffset] & 0x03) &&
+			aEpInfo.iInterval == epDescriptor[KEpDesc_IntervalOffset]);
+			
+	// Change the endpoint poll interval
+	TUint8 ival = 0x66;
+	if (epDescriptor[KEpDesc_IntervalOffset] == ival)
+		ival++;
+
+
+	TUint8 saveAddr = 0;										// save the address
+	if (aEpInfo.iExtra > 0)
+		{
+		saveAddr = epDescriptor[KEpDesc_SynchAddressOffset];
+		TUint8 addr = 0x85;										// bogus address
+		if (epDescriptor[KEpDesc_SynchAddressOffset] == addr)
+			addr++;
+		epDescriptor[KEpDesc_SynchAddressOffset] = addr;
+		}
+
+	epDescriptor[KEpDesc_IntervalOffset] = ival;
+	r = aPort->SetEndpointDescriptor(aIfSetting, aEpNumber, epDescriptor);
+	test_KErrNone(r);
+
+	TBuf8<KUsbDescSize_AudioEndpoint> descriptor2;
+	r = aPort->GetEndpointDescriptor(aIfSetting, aEpNumber, descriptor2);
+	test_KErrNone(r);
+
+	r = descriptor2.Compare(epDescriptor);
+	test_KErrNone(r);
+
+	if (aEpInfo.iExtra > 0)
+		{
+		// Restore the endpoint synch address
+		epDescriptor[KEpDesc_SynchAddressOffset] = saveAddr;
+		}
+
+	// Restore the endpoint poll interval
+	epDescriptor[KEpDesc_IntervalOffset] = aEpInfo.iInterval;
+	r = aPort->SetEndpointDescriptor(aIfSetting, aEpNumber, epDescriptor);
+	test_KErrNone(r);
+
+	test.End();
+	}
+
+static void TestStandardStringDescriptors(RDEVCLIENT* aPort)
+	{
+	test.Start(_L("String Descriptor Manipulation"));
+
+	//
+	// --- LANGID code
+	//
+
+	test.Next(_L("GetStringDescriptorLangId()"));
+	TUint16 rd_langid_orig;
+	TInt r = aPort->GetStringDescriptorLangId(rd_langid_orig);
+	test_KErrNone(r);
+	test.Printf(_L("Original LANGID code: 0x%04X\n"), rd_langid_orig);
+
+	test.Next(_L("SetStringDescriptorLangId()"));
+	TUint16 wr_langid = 0x0809;								// English (UK) Language ID
+	if (wr_langid == rd_langid_orig)
+		wr_langid = 0x0444;									// Tatar Language ID
+	r = aPort->SetStringDescriptorLangId(wr_langid);
+	test_KErrNone(r);
+
+	test.Next(_L("GetStringDescriptorLangId()"));
+	TUint16 rd_langid;
+	r = aPort->GetStringDescriptorLangId(rd_langid);
+	test_KErrNone(r);
+	test.Printf(_L("New LANGID code: 0x%04X\n"), rd_langid);
+
+	test.Next(_L("Compare LANGID codes"));
+	test_Equal(wr_langid,rd_langid);
+
+	test.Next(_L("Restore original LANGID code"));
+	r = aPort->SetStringDescriptorLangId(rd_langid_orig);
+	test_KErrNone(r);
+	r = aPort->GetStringDescriptorLangId(rd_langid);
+	test_KErrNone(r);
+	test_Equal(rd_langid_orig,rd_langid);
+
+	//
+	// --- Manufacturer string
+	//
+
+	test.Next(_L("GetManufacturerStringDescriptor()"));
+	TBuf16<KUsbStringDescStringMaxSize / 2> rd_str_orig;
+	r = aPort->GetManufacturerStringDescriptor(rd_str_orig);
+	test(r == KErrNone || r == KErrNotFound);
+	TBool restore_string;
+	if (r == KErrNone)
+		{
+		test.Printf(_L("Original Manufacturer string: \"%lS\"\n"), &rd_str_orig);
+		restore_string = ETrue;
+		}
+	else
+		{
+		test.Printf(_L("No Manufacturer string set\n"));
+		restore_string = EFalse;
+		}
+
+	test.Next(_L("SetManufacturerStringDescriptor()"));
+	_LIT16(manufacturer, "Manufacturer Which Manufactures Devices");
+	TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(manufacturer);
+	r = aPort->SetManufacturerStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetManufacturerStringDescriptor()"));
+	TBuf16<KUsbStringDescStringMaxSize / 2> rd_str;
+	r = aPort->GetManufacturerStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Manufacturer string: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Manufacturer strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("SetManufacturerStringDescriptor()"));
+	_LIT16(manufacturer2, "Different Manufacturer Which Manufactures Different Devices");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = manufacturer2;
+	r = aPort->SetManufacturerStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetManufacturerStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetManufacturerStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Manufacturer string: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Manufacturer strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("RemoveManufacturerStringDescriptor()"));
+	r = aPort->RemoveManufacturerStringDescriptor();
+	test_KErrNone(r);
+	r = aPort->GetManufacturerStringDescriptor(rd_str);
+	test_Equal(KErrNotFound,r);
+
+	if (restore_string)
+		{
+		test.Next(_L("Restore original string"));
+		r = aPort->SetManufacturerStringDescriptor(rd_str_orig);
+		test_KErrNone(r);
+		r = aPort->GetManufacturerStringDescriptor(rd_str);
+		test_KErrNone(r);
+		r = rd_str.Compare(rd_str_orig);
+		test_KErrNone(r);
+		}
+
+	//
+	// --- Product string
+	//
+
+	test.Next(_L("GetProductStringDescriptor()"));
+	rd_str_orig.FillZ(rd_str.MaxLength());
+	r = aPort->GetProductStringDescriptor(rd_str_orig);
+	test(r == KErrNone || r == KErrNotFound);
+	if (r == KErrNone)
+		{
+		test.Printf(_L("Old Product string: \"%lS\"\n"), &rd_str_orig);
+		restore_string = ETrue;
+		}
+	else
+		restore_string = EFalse;
+
+	test.Next(_L("SetProductStringDescriptor()"));
+	_LIT16(product, "Product That Was Produced By A Manufacturer");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = product;
+	r = aPort->SetProductStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetProductStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetProductStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Product string: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Product strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("SetProductStringDescriptor()"));
+	_LIT16(product2, "Different Product That Was Produced By A Different Manufacturer");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = product2;
+	r = aPort->SetProductStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetProductStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetProductStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Product string: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Product strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("RemoveProductStringDescriptor()"));
+	r = aPort->RemoveProductStringDescriptor();
+	test_KErrNone(r);
+	r = aPort->GetProductStringDescriptor(rd_str);
+	test_Equal(KErrNotFound,r);
+
+	if (restore_string)
+		{
+		test.Next(_L("Restore original string"));
+		r = aPort->SetProductStringDescriptor(rd_str_orig);
+		test_KErrNone(r);
+		r = aPort->GetProductStringDescriptor(rd_str);
+		test_KErrNone(r);
+		r = rd_str.Compare(rd_str_orig);
+		test_KErrNone(r);
+		}
+
+	//
+	// --- Serial Number string
+	//
+
+	test.Next(_L("GetSerialNumberStringDescriptor()"));
+	rd_str_orig.FillZ(rd_str.MaxLength());
+	r = aPort->GetSerialNumberStringDescriptor(rd_str_orig);
+	test(r == KErrNone || r == KErrNotFound);
+	if (r == KErrNone)
+		{
+		test.Printf(_L("Old Serial Number: \"%lS\"\n"), &rd_str_orig);
+		restore_string = ETrue;
+		}
+	else
+		restore_string = EFalse;
+
+	test.Next(_L("SetSerialNumberStringDescriptor()"));
+	_LIT16(serial, "000666000XYZ");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = serial;
+	r = aPort->SetSerialNumberStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetSerialNumberStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetSerialNumberStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Serial Number: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Serial Number strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("SetSerialNumberStringDescriptor()"));
+	_LIT16(serial2, "Y11611193111711111Y");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = serial2;
+	r = aPort->SetSerialNumberStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetSerialNumberStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetSerialNumberStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Serial Number: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Serial Number strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("RemoveSerialNumberStringDescriptor()"));
+	r = aPort->RemoveSerialNumberStringDescriptor();
+	test_KErrNone(r);
+	r = aPort->GetSerialNumberStringDescriptor(rd_str);
+	test_Equal(KErrNotFound,r);
+
+	if (restore_string)
+		{
+		test.Next(_L("Restore original string"));
+		r = aPort->SetSerialNumberStringDescriptor(rd_str_orig);
+		test_KErrNone(r);
+		r = aPort->GetSerialNumberStringDescriptor(rd_str);
+		test_KErrNone(r);
+		r = rd_str.Compare(rd_str_orig);
+		test_KErrNone(r);
+		}
+
+	//
+	// --- Configuration string
+	//
+
+	test.Next(_L("GetConfigurationStringDescriptor()"));
+	rd_str_orig.FillZ(rd_str.MaxLength());
+	r = aPort->GetConfigurationStringDescriptor(rd_str_orig);
+	test(r == KErrNone || r == KErrNotFound);
+	if (r == KErrNone)
+		{
+		test.Printf(_L("Old Configuration string: \"%lS\"\n"), &rd_str_orig);
+		restore_string = ETrue;
+		}
+	else
+		restore_string = EFalse;
+
+	test.Next(_L("SetConfigurationStringDescriptor()"));
+	_LIT16(config, "Relatively Simple Configuration That Is Still Useful");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = config;
+	r = aPort->SetConfigurationStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetConfigurationStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetConfigurationStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Configuration string: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Configuration strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("SetConfigurationStringDescriptor()"));
+	_LIT16(config2, "Convenient Configuration That Can Be Very Confusing");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = config2;
+	r = aPort->SetConfigurationStringDescriptor(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("GetConfigurationStringDescriptor()"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetConfigurationStringDescriptor(rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New Configuration string: \"%lS\"\n"), &rd_str);
+
+	test.Next(_L("Compare Configuration strings"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	test.Next(_L("RemoveConfigurationStringDescriptor()"));
+	r = aPort->RemoveConfigurationStringDescriptor();
+	test_KErrNone(r);
+	r = aPort->GetConfigurationStringDescriptor(rd_str);
+	test_Equal(KErrNotFound,r);
+
+	if (restore_string)
+		{
+		test.Next(_L("Restore original string"));
+		r = aPort->SetConfigurationStringDescriptor(rd_str_orig);
+		test_KErrNone(r);
+		r = aPort->GetConfigurationStringDescriptor(rd_str);
+		test_KErrNone(r);
+		r = rd_str.Compare(rd_str_orig);
+		test_KErrNone(r);
+		}
+
+	test.End();
+	}
+
+
+static void TestArbitraryStringDescriptors(RDEVCLIENT* aPort,TInt aNumSettings)
+	{
+	test.Start(_L("Arbitrary String Descriptor Manipulation"));
+
+	// First test string
+
+	test.Next(_L("GetStringDescriptor() 1"));
+	TBuf16<KUsbStringDescStringMaxSize / 2> rd_str;
+	TInt r = aPort->GetStringDescriptor(stridx1, rd_str);
+	test_KErrNone(r);
+
+	TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(KString_one);
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	// Second test string
+
+	test.Next(_L("GetStringDescriptor() 2"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetStringDescriptor(stridx2, rd_str);
+	test_KErrNone(r);
+
+	wr_str = KString_two;
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	// Third test string
+
+	test.Next(_L("GetStringDescriptor() 3"));
+	rd_str.FillZ(rd_str.MaxLength());
+	r = aPort->GetStringDescriptor(stridx3, rd_str);
+	test_Equal(KErrNotFound,r);
+
+	test.Next(_L("SetStringDescriptor() 3"));
+	_LIT16(string_three, "Arbitrary String Descriptor Test String 3");
+	wr_str.FillZ(wr_str.MaxLength());
+	wr_str = string_three;
+	r = aPort->SetStringDescriptor(stridx3, wr_str);
+	test_KErrNone(r);
+
+	// In between we create another interface setting to see what happens
+	// to the existing string descriptor indices.
+	// (We don't have to test this on every platform -
+	// besides, those that don't support alt settings
+	// are by now very rare.)
+	if (SupportsAlternateInterfaces())
+		{
+		#ifdef USB_SC
+		TUsbcScInterfaceInfoBuf ifc;
+		#else
+		TUsbcInterfaceInfoBuf ifc;
+		#endif
+		_LIT16(string, "T_USB_DEVICE Bogus Test Interface (Next Setting)");
+		ifc().iString = const_cast<TDesC16*>(&string);
+		ifc().iTotalEndpointsUsed = 0;
+		TInt r = aPort->SetInterface(aNumSettings, ifc);
+		test_KErrNone(r);
+		}
+
+	test.Next(_L("GetStringDescriptor() 3"));
+	r = aPort->GetStringDescriptor(stridx3, rd_str);
+	test_KErrNone(r);
+	test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx3, &rd_str);
+
+	test.Next(_L("Compare test strings 3"));
+	r = rd_str.Compare(wr_str);
+	test_KErrNone(r);
+
+	// Remove string descriptors 3 and 4
+
+	test.Next(_L("RemoveStringDescriptor() 4"));
+	r = aPort->RemoveStringDescriptor(stridx4);
+	test_Equal(KErrNotFound,r);
+
+	test.Next(_L("RemoveStringDescriptor() 3"));
+	r = aPort->RemoveStringDescriptor(stridx3);
+	test_KErrNone(r);
+
+	r = aPort->GetStringDescriptor(stridx3, rd_str);
+	test_Equal(KErrNotFound,r);
+
+	if (SupportsAlternateInterfaces())
+		{
+		TInt r = aPort->ReleaseInterface(aNumSettings);
+		test_KErrNone(r);
+		}
+
+	test.End();
+	}
+
+void TestInvalidSetInterface (RDEVCLIENT* aPort,TInt aNumSettings)
+	{
+	#ifdef USB_SC
+	TUsbcScInterfaceInfoBuf ifc;
+	#else
+	TUsbcInterfaceInfoBuf ifc;
+	#endif
+	_LIT16(string, "T_USB_DEVICE Invalid Interface");
+	ifc().iString = const_cast<TDesC16*>(&string);
+	ifc().iTotalEndpointsUsed = 0;
+
+	test.Start(_L("Test Invalid Interface Setting"));
+
+	if (SupportsAlternateInterfaces())
+		{
+		TInt r = aPort->SetInterface(aNumSettings+1, ifc);
+		test_Compare(r,!=,KErrNone);		
+		}
+	
+	if (aNumSettings > 1)
+		{
+		TInt r = aPort->SetInterface(aNumSettings-1, ifc);
+		test_Compare(r,!=,KErrNone);		
+		}
+
+	TInt r = aPort->SetInterface(0, ifc);
+	test_Compare(r,!=,KErrNone);		
+
+	test.End();
+	}
+
+void TestInvalidReleaseInterface (RDEVCLIENT* aPort,TInt aNumSettings)
+	{
+	test.Start(_L("Test Invalid Interface Release"));
+
+	if (aNumSettings > 2)
+		{
+		TInt r = aPort->ReleaseInterface(aNumSettings-3);
+		test_Compare(r,!=,KErrNone);		
+		}
+
+	if (aNumSettings > 1)
+		{
+		TInt r = aPort->ReleaseInterface(aNumSettings-2);
+		test_Compare(r,!=,KErrNone);		
+		}
+
+	test.End();
+	}
+
+void TestDescriptorManipulation(TBool aHighSpeed, RDEVCLIENT* aPort, TInt aNumSettings)
+	{
+	test.Start(_L("Test USB Descriptor Manipulation"));
+
+	if (aHighSpeed)
+		{
+		TestDeviceQualifierDescriptor(aPort);
+
+		TestOtherSpeedConfigurationDescriptor(aPort);	
+		}
+
+	TestInterfaceDescriptor(aPort,aNumSettings);
+
+	TestClassSpecificDescriptors(aPort);
+
+	TestStandardStringDescriptors(aPort);
+
+	TestArbitraryStringDescriptors(aPort,aNumSettings);
+
+	test.End();
+	}
+
+
+void TestOtgExtensions(RDEVCLIENT* aPort)
+	{
+	test.Start(_L("Test Some OTG API Extensions"));
+
+	// Test OTG descriptor manipulation
+	test.Next(_L("Get OTG Descriptor Size"));
+	TInt size;
+	aPort->GetOtgDescriptorSize(size);
+	test_Equal(KUsbDescSize_Otg,static_cast<TUint>(size));
+
+	test.Next(_L("Get OTG Descriptor"));
+	TBuf8<KUsbDescSize_Otg> otgDesc;
+	TInt r = aPort->GetOtgDescriptor(otgDesc);
+	test(r == KErrNotSupported || r == KErrNone);
+
+	test.Next(_L("Set OTG Descriptor"));
+	TBool supportOtg = EFalse;
+	if (r == KErrNotSupported)
+		{
+		r = aPort->SetOtgDescriptor(otgDesc);
+		test_Equal(KErrNotSupported,r);
+		}
+	else
+		{
+		supportOtg = ETrue;
+		otgDesc[0] = KUsbDescSize_Otg;
+		otgDesc[1] = KUsbDescType_Otg;
+		otgDesc[2] = KUsbOtgAttr_SrpSupp;
+		r = aPort->SetOtgDescriptor(otgDesc);
+		test_KErrNone(r);
+		TBuf8<KUsbDescSize_Otg> desc;
+		r = aPort->GetOtgDescriptor(desc);
+		test_KErrNone(r);
+		test_Equal(0,desc.Compare(otgDesc));
+		}
+
+	// Test get/set OTG feature
+	test.Next(_L("Get OTG Features"));
+	TUint8 features;
+	r = aPort->GetOtgFeatures(features);
+	if (supportOtg)
+		{
+		test_KErrNone(r);
+		TBool b_HnpEnable = (features & KUsbOtgAttr_B_HnpEnable) ? ETrue : EFalse;
+		TBool a_HnpSupport = (features & KUsbOtgAttr_A_HnpSupport) ? ETrue : EFalse;
+		TBool a_AltHnpSupport = (features & KUsbOtgAttr_A_AltHnpSupport) ? ETrue : EFalse;
+		test.Printf(_L("### OTG Features:\nB_HnpEnable(%d)\nA_HnpSupport(%d)\nA_Alt_HnpSupport(%d)\n"),
+					b_HnpEnable, a_HnpSupport, a_AltHnpSupport);
+		}
+	else
+		{
+		test_Equal(KErrNotSupported,r);
+		test.Printf(_L("GetOtgFeatures() not supported\n"));
+		}
+
+	test.End();
+}
+
+
+void TestEndpoint0MaxPacketSizes(RDEVCLIENT* aPort)
+	{
+	test.Start(_L("Test Endpoint0 MaxPacketSizes"));
+
+	TUint32 sizes = aPort->EndpointZeroMaxPacketSizes();
+	TInt r = KErrNone;
+	TBool good;
+	TInt mpsize = 0;
+	for (TInt i = 0; i < 32; i++)
+		{
+		TUint bit = sizes & (1 << i);
+		if (bit != 0)
+			{
+			switch (bit)
+				{
+			case KUsbEpSizeCont:
+				good = EFalse;
+				break;
+			case KUsbEpSize8:
+				mpsize = 8;
+				good = ETrue;
+				break;
+			case KUsbEpSize16:
+				mpsize = 16;
+				good = ETrue;
+				break;
+			case KUsbEpSize32:
+				mpsize = 32;
+				good = ETrue;
+				break;
+			case KUsbEpSize64:
+				mpsize = 64;
+				good = ETrue;
+				break;
+			case KUsbEpSize128:
+			case KUsbEpSize256:
+			case KUsbEpSize512:
+			case KUsbEpSize1023:
+			default:
+				good = EFalse;
+				break;
+				}
+			if (good)
+				{
+				test.Printf(_L("Ep0 supports %d bytes MaxPacketSize\n"), mpsize);
+				}
+			else
+				{
+				test.Printf(_L("Bad Ep0 size: 0x%08x, failure will occur\n"), bit);
+				r = KErrGeneral;
+				}
+			}
+		}
+	test_KErrNone(r);
+
+    test.End();
+	}
+
+