kerneltest/e32test/usbho/t_usbdi/src/TestDeviceBase.cpp
changeset 0 a41df078684a
child 253 d37db4dcc88d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/usbho/t_usbdi/src/TestDeviceBase.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,696 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of 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:
+// @file testdevicebase.cpp
+// @internalComponent
+// 
+//
+
+#include "TestDeviceBase.h"
+#include "UsbDescriptorOffsets.h"
+#include "testdebug.h"
+#include <e32test.h>
+#include "softwareconnecttimer.h"
+#include "wakeuptimer.h"
+#include "controltransferrequests.h"
+#include "testinterfacebase.h"
+#include "PBASE-T_USBDI-0486.h"
+#include <e32property.h>
+
+namespace NUnitTesting_USBDI
+	{
+
+RUsbTestDevice::RUsbTestDevice()
+: 	iStateWatcher(NULL), 
+	iCurrentState(EUsbcDeviceStateUndefined), 
+	iDeviceEp0(NULL), 
+	iConnectTimer(NULL), iWakeupTimer(NULL),
+	iAuxBuffer(NULL)
+	{
+	}
+	
+RUsbTestDevice::RUsbTestDevice(CBaseTestCase* aTestCase)
+: 	iStateWatcher(NULL), 
+	iCurrentState(EUsbcDeviceStateUndefined), 
+	iDeviceEp0(NULL), 
+	iConnectTimer(NULL), iWakeupTimer(NULL),
+	iAuxBuffer(NULL)
+	{
+	LOG_FUNC	
+	iTestCase = aTestCase;
+	RDebug::Printf("iTestCase = %d", iTestCase);
+	}
+		
+void RUsbTestDevice::ResetState()
+	{
+	iCurrentState = EUsbcDeviceStateUndefined;
+	}
+
+RUsbTestDevice::~RUsbTestDevice()
+	{
+	LOG_FUNC
+	
+	}
+	
+void RUsbTestDevice::Close()
+	{
+	LOG_FUNC
+
+	delete iWakeupTimer;
+	delete iConnectTimer;
+	delete iDeviceEp0;
+	delete iStateWatcher;
+		
+	iInterfaces.ResetAndDestroy();
+
+	iClientDriver.Close(); 
+	
+	if(!iTestCase->IsHost()) // process only started in client rom
+		{
+        // create a publish/subscribe key to allow usbhost_usbman to be killed
+        // cleanly
+        static const TUid KWordOfDeathCat = {0x01066600};
+        static const TInt KWordOfDeathKey = 0x01066601;
+        static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy);
+        TInt r = RProperty::Define(KWordOfDeathCat, KWordOfDeathKey, RProperty::EInt,KAllowAllPolicy, KAllowAllPolicy, 0);
+        if(r != KErrNone)
+            {
+            RDebug::Print(_L("Could not create the WordOfDeath P&S   (%d)"), r);
+            }
+		RDebug::Printf("killing t_usbhost_usbman.exe");
+        RProperty::Set(KWordOfDeathCat, KWordOfDeathKey, KErrAbort);   // Send the word of death
+        User::After(1000000); //allow time for t_usbhost_usbman.exe to clean up
+		}
+	}
+
+
+void RUsbTestDevice::SubscribeToReports(TRequestStatus& aObserverStatus)
+	{
+	LOG_FUNC
+	
+	// Signal the request as pending
+	
+	iObserverStatus = &aObserverStatus;
+	*iObserverStatus = KRequestPending;
+	}
+
+
+void RUsbTestDevice::CancelSubscriptionToReports()
+	{
+	LOG_FUNC
+	
+	// Signal the request as cancelled
+	User::RequestComplete(iObserverStatus,KErrCancel);
+	}
+	
+		
+void RUsbTestDevice::OpenL()
+	{
+	LOG_FUNC	
+	TInt err = KErrNone;
+	
+	RDebug::Printf("starting t_usbhost_usbman.exe");
+	TInt r = iOtgUsbMan.Create(_L("t_usbhost_usbman.exe"), _L("client"));
+	gtest(r == KErrNone);
+	iOtgUsbMan.Resume();	
+	
+	User::After(1500000);
+	
+	// Open channel to driver
+	err = iClientDriver.Open(0);
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to open a channel to USB client driver",err);
+		User::Leave(err);
+		}
+	
+	// Hide bus from host while interfaces are being set up
+	err = iClientDriver.DeviceDisconnectFromHost();
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> unable to disconnect device from host",err);
+		User::Leave(err);
+		}
+	
+	// Create the client usb state watcher
+	iStateWatcher = CUsbClientStateWatcher::NewL(iClientDriver,*this);
+		
+	// Create the Ep0 reader
+	iDeviceEp0 = CDeviceEndpoint0::NewL(*this);
+		
+	// Create the timer for software connection/disconnection
+	iConnectTimer = CSoftwareConnectTimer::NewL(*this);
+	
+	// Create the timer for remote wakeup events
+	iWakeupTimer = CRemoteWakeupTimer::NewL(*this);
+	_LIT8(KYes, "yes");
+	_LIT8(KNo, "no");
+	User::LeaveIfError(iClientDriver.DeviceCaps(iDeviceCaps));
+ 	RDebug::Printf("------ USB device capabilities -------");
+	RDebug::Printf("Number of endpoints:                %d",iDeviceCaps().iTotalEndpoints);	
+	RDebug::Printf("Supports Software-Connect:          %S",iDeviceCaps().iConnect ? &KYes() : &KNo());
+	RDebug::Printf("Device is Self-Powered:             %S",iDeviceCaps().iSelfPowered ? &KYes() : &KNo());
+	RDebug::Printf("Supports Remote-Wakeup:             %S",iDeviceCaps().iRemoteWakeup ? &KYes() : &KNo());
+	RDebug::Printf("Supports High-speed:                %S",iDeviceCaps().iHighSpeed ? &KYes() : &KNo());
+	RDebug::Printf("Supports unpowered cable detection: %S",(iDeviceCaps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ? &KYes() : &KNo());
+	RDebug::Printf("--------------------------------------");
+	
+	}
+
+
+TInt RUsbTestDevice::SetClassCode(TUint8 aClassCode,TUint8 aSubClassCode,TUint8 aDeviceProtocol)
+	{
+	LOG_FUNC
+
+	// Get Device descriptor
+	TBuf8<KUsbDescSize_Device> deviceDescriptor;
+	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to obtain device descriptor",err);
+		}
+	else
+		{
+		deviceDescriptor[KDevDescOffset_bDeviceClass] = aClassCode;
+		deviceDescriptor[KDevDescOffset_bDeviceSubClass] = aSubClassCode;
+		deviceDescriptor[KDevDescOffset_bDeviceProtocol] = aDeviceProtocol;	
+		
+		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set the device dsecriptor",err);
+			}
+		}
+	return err;
+	}
+
+
+TInt RUsbTestDevice::SetUsbSpecification(TUint16 aSpecification)
+	{
+	LOG_FUNC
+
+	// Get Device descriptor
+	TBuf8<KUsbDescSize_Device> deviceDescriptor;
+	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to obtain device descriptor",err);
+		}
+	else
+		{
+		// Set bcdUSB
+		TUint8* p = reinterpret_cast<TUint8*>(&aSpecification);
+		deviceDescriptor[KDevDescOffset_bcdUSB] = *p;
+		deviceDescriptor[KDevDescOffset_bcdUSB+1] = *(p+1);
+		
+		// Symbian currently supports only devices with one configuration by selecting the configurations
+		// that has the lowest power consumption
+		
+		deviceDescriptor[KDevDescOffset_bNumConfigurations] = 0x01;
+		
+		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set the device dsecriptor",err);
+			}
+		}
+	return err;
+	}
+
+
+TInt RUsbTestDevice::SetVendor(TUint16 aVendorId)
+	{
+	LOG_FUNC
+
+	// Get Device descriptor
+	TBuf8<KUsbDescSize_Device> deviceDescriptor;
+	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to obtain device descriptor",err);
+		}
+	else
+		{
+		// Set VID
+		TUint8* p = reinterpret_cast<TUint8*>(&aVendorId);
+		deviceDescriptor[KDevDescOffset_idVendor] = *p;
+		deviceDescriptor[KDevDescOffset_idVendor+1] = *(p+1);
+		
+		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set the device descriptor",err);
+			}
+		}
+	return err;
+	}
+
+
+TInt RUsbTestDevice::SetProduct(TUint16 aProductId,const TDesC16& aProductString,
+				const TDesC16& aManufacturerString,const TDesC16& aSerialNumberString)
+	{
+	LOG_FUNC
+
+	// Get Device descriptor
+	TBuf8<KUsbDescSize_Device> deviceDescriptor;
+	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to obtain device descriptor",err);
+		}
+	else
+		{
+		// Set PID
+		TUint8* p = reinterpret_cast<TUint8*>(&aProductId);
+		deviceDescriptor[KDevDescOffset_idProduct] = *p;
+		deviceDescriptor[KDevDescOffset_idProduct+1] = *(p+1);
+		
+		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set the device dsecriptor",err);
+			return err;
+			}
+		
+		RDebug::Printf("Product Identity set");
+	
+		// Product string
+		err = iClientDriver.SetProductStringDescriptor(aProductString);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set product string descriptor",err);
+			return err;
+			}
+
+		// Manufacturer string
+		err = iClientDriver.SetManufacturerStringDescriptor(aManufacturerString);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set the manufacturer string descriptor",err);
+			return err;
+			}
+	
+		// Serial number string
+		err = iClientDriver.SetSerialNumberStringDescriptor(aSerialNumberString);
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to set the serial number string descriptor",err);
+			return err;
+			}
+		}
+	return KErrNone;
+	}
+
+
+TInt RUsbTestDevice::SetConfigurationString(const TDesC16& aConfigString)
+	{
+	LOG_FUNC
+
+	TInt err(iClientDriver.SetConfigurationStringDescriptor(aConfigString));
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to set configuration string descriptor",err);
+		}
+	return err;
+	}
+
+
+void RUsbTestDevice::AddInterface(CInterfaceBase* aInterface)
+	{
+	LOG_FUNC
+		
+	// Add the interface to the device
+	TInt err = iInterfaces.Append(aInterface);
+	
+	if(err != KErrNone)
+		{
+		RDebug::Printf("<Error %d> Unable to add interface",err);
+		return ReportError(err);
+		}
+	}
+
+
+CInterfaceBase& RUsbTestDevice::Interface(TInt aIndex)
+	{
+	return *iInterfaces[aIndex];
+	}
+
+
+void RUsbTestDevice::SoftwareConnect()
+	{
+	LOG_FUNC
+	TInt err(iClientDriver.PowerUpUdc());
+	if((err != KErrNone) && (err != KErrNotReady))
+		{
+		RDebug::Printf("<Error %d> Power Up Udc",err);
+		ReportError(err);
+		}
+		
+	if(iDeviceCaps().iConnect) 
+		{
+		err = iClientDriver.DeviceConnectToHost();
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to connect to the host",err);
+			ReportError(err);
+			}
+		}
+	else
+		{
+		RDebug::Printf("Please connect device to Host");
+		}	
+	}   	
+	 
+void RUsbTestDevice::SoftwareDisconnect()
+	{
+	LOG_FUNC
+	
+	if(iDeviceCaps().iConnect) 
+		{
+		TInt err(iClientDriver.DeviceDisconnectFromHost());
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to disconnect from the host",err);
+			ReportError(err);
+			}
+		}
+	else
+		{
+		RDebug::Printf("Please disconnect device from Host");
+		}
+		
+	}       
+
+
+void RUsbTestDevice::RemoteWakeup()
+	{
+	LOG_FUNC
+	if(iDeviceCaps().iConnect) 
+		{
+		TInt err(iClientDriver.SignalRemoteWakeup());
+		if(err != KErrNone)
+			{
+			RDebug::Printf("<Error %d> Unable to perform a remote wakeup",err);
+			ReportError(err);
+			}
+		}
+	else
+		{
+		RDebug::Printf("remote wakeup not supported");
+		}
+	}
+
+
+TInt RUsbTestDevice::ProcessRequestL(TUint8 aRequest,TUint16 aValue,TUint16 aIndex,
+	TUint16 aDataReqLength,const TDesC8& aPayload)
+	{
+	LOG_FUNC
+	
+	if(aRequest == KVendorEmptyRequest)
+		{
+		// Handle an empty request (i.e. do nothing)
+		
+		AcknowledgeRequestReceived();
+		}
+	else if(aRequest == KVendorReconnectRequest)
+		{
+		// Handle a reconnect requests from the host
+		
+		AcknowledgeRequestReceived();
+		iConnectTimer->SoftwareReConnect(aValue);
+		}
+	else if(aRequest == KVendorDisconnectDeviceAThenConnectDeviceCRequest)
+		{
+		RDebug::Printf("**aRequest == KVendorDisconnectDeviceAThenConnectDeviceCRequest, this = 0x%08x", this);
+		// Handle a reconnect requests from the host		
+		AcknowledgeRequestReceived();			
+		
+		SoftwareDisconnect();	
+		User::After(1000000);
+		//	connect device C now	
+		CUT_PBASE_T_USBDI_0486* iTestCaseT_USBDI_0486 = reinterpret_cast<CUT_PBASE_T_USBDI_0486*>(iTestCase);
+		Close(); 		
+		
+		User::After(3000000);
+		iTestCaseT_USBDI_0486->TestDeviceC()->OpenL(KTestDeviceC_SN);		
+		// Connect the device to the host	
+		iTestCaseT_USBDI_0486->TestDeviceC()->SoftwareConnect();
+		return KErrAbort;
+		}
+	else if(aRequest == KVendorDisconnectDeviceCThenConnectDeviceARequest)
+		{
+		RDebug::Printf("**aRequest == KVendorDisconnectDeviceCThenConnectDeviceARequest, this = 0x%08x", this);
+		// Handle a reconnect requests from the host		
+		AcknowledgeRequestReceived();		
+		 
+		SoftwareDisconnect();	
+		User::After(1000000); 
+		 
+		//	connect device A now	
+		CUT_PBASE_T_USBDI_0486* iTestCaseT_USBDI_0486 = reinterpret_cast<CUT_PBASE_T_USBDI_0486*>(iTestCase);
+		
+		
+		Close();		
+		User::After(3000000); 		
+		iTestCaseT_USBDI_0486->Cancel();
+		iTestCaseT_USBDI_0486->HandleDeviceDConnection();
+		iTestCaseT_USBDI_0486->TestDeviceD()->OpenL(iTestCaseT_USBDI_0486->TestCaseId());	
+		
+		// Connect the device to the host	
+		iTestCaseT_USBDI_0486->TestDeviceD()->SoftwareConnect();	
+		return KErrAbort;
+		}		
+	else if(aRequest == KVendorTestCasePassed)
+		{ 
+		// Test case has completed successfully 
+		// so report to client test case that host is happy		
+		
+		AcknowledgeRequestReceived();
+		ReportError(KErrNone);
+		}
+	else if(aRequest == KVendorTestCaseFailed)
+		{
+		// The test case has failed, so report to client test case
+		// and display/log the error message
+		
+		AcknowledgeRequestReceived();
+		
+		HBufC16* msg = HBufC16::NewL(aPayload.Length());
+		msg->Des().Copy(aPayload);
+		RDebug::Printf("<Host> Test case failed: %S",msg);
+		delete msg;
+		msg = 0;
+		ReportError(-aValue);
+		}
+	else if(aRequest == KVendorRemoteWakeupRequest)
+		{
+		// Handle a remote wakeup request
+
+		AcknowledgeRequestReceived();
+		iWakeupTimer->WakeUp(aValue);
+		}
+	else if(aRequest == KVendorPutPayloadRequest)
+		{
+		// Handle a payload request from the host
+
+		AcknowledgeRequestReceived();
+		RDebug::Printf("Put payload");
+		if(aPayload.Compare(_L8("DEADBEEF")) != 0)
+			{
+			RDebug::Printf("<Error %d> Payload not as expected",KErrCorrupt);
+			ReportError(KErrCorrupt);
+			}
+		}
+	else if(aRequest == KVendorGetPayloadRequest)
+		{
+		// Handle a payload request to the host
+
+		RDebug::Printf("Get payload");
+		__ASSERT_DEBUG(iAuxBuffer, User::Panic(_L("Trying to write non-allocated buffer"), KErrGeneral));
+		RDebug::Printf("iAuxBuffer = ....");
+		RDebug::RawPrint(*iAuxBuffer);
+		RDebug::Printf("\n");
+		
+		//Perform synchronous write to EP0
+		//This allows the subsequent 'Read' request to
+		//take place
+		TInt ret = iDeviceEp0->SendDataSynchronous(*iAuxBuffer);
+		RDebug::Printf("Write (from device callback) executed with error %d", ret);
+		}
+	else if(aRequest == KVendorUnrespondRequest)
+		{
+		// Do not acknowledge this request
+		
+		RDebug::Printf("Unrespond request: continually NAK the host");
+		}
+	else if(aRequest == KVendorStallRequest)
+		{
+		// Stall the specified endpoint
+		
+		AcknowledgeRequestReceived();
+		RDebug::Printf("Stalling endpoint %d",aValue);
+						
+		}
+	else
+		{
+		// Maybe forward to derived classes
+		}
+	return KErrNone;
+	}
+
+
+void RUsbTestDevice::StateChangeL(TUsbcDeviceState aNewState,TInt aChangeCompletionCode)
+	{
+	LOG_FUNC
+	
+	RDebug::Printf("Client state change to %d err=%d",aNewState,aChangeCompletionCode);
+	
+	// Notify the test case of failed state change notification
+	
+	if(aChangeCompletionCode != KErrNone)
+		{
+		return ReportError(aChangeCompletionCode);
+		}
+	
+	// Check the state change
+	
+	if(iCurrentState == EUsbcDeviceStateConfigured)
+		{
+		// Device is already in a fully configured state
+		
+		if(aNewState == EUsbcDeviceStateConfigured)
+			{
+			// Do nothing as this is the current state anyway
+			}
+		else
+			{
+			// The is a state change from EUsbcDeviceStateConfigured to aNewState
+			// so stop reading from control ep0
+			
+			RDebug::Printf("Ignoring control ep0");
+			
+			// Stop reading ep0 directed requests
+			
+			StopEp0Reading();
+			
+			// Update state
+						
+			iCurrentState = aNewState;
+			}
+		}
+	else
+		{
+		// Device is not in a fully configured state
+		
+		if(aNewState == EUsbcDeviceStateConfigured)
+			{
+			// Device has now been placed into a fully configured state by the host
+			// so start reading from control ep0
+			
+			RDebug::Printf("Reading from control ep0");
+			
+			// Start reading ep0 directed requests
+			
+			StartEp0Reading();
+			
+			// Update state
+						
+			iCurrentState = aNewState;
+			}
+		else
+			{
+			// Just update the state
+			
+			iCurrentState = aNewState;
+			}
+		}
+				
+	// Forward the state change notification to derived classes
+	
+	OnStateChangeL(aNewState);
+	}
+	
+
+void RUsbTestDevice::StartEp0Reading()
+	{
+	LOG_FUNC
+
+	// Start reading device directed ep0 requests
+	
+	TInt err(iDeviceEp0->Start());
+	if(err != KErrNone)
+		{
+		return ReportError(err);
+		}
+		
+	// Start reading interface directed requests
+			
+	TInt interfaceCount(iInterfaces.Count());
+	for(TInt i=0; i<interfaceCount; i++)
+		{
+		iInterfaces[i]->StartEp0Reading();
+		}
+	}
+
+
+void RUsbTestDevice::StopEp0Reading()
+	{
+	LOG_FUNC
+
+	// Stop reading interface directed requests
+	
+	TInt interfaceCount(iInterfaces.Count());
+	for(TInt i=0; i<interfaceCount; i++)
+		{
+		iInterfaces[i]->StopEp0Reading();
+		}
+		
+	// Stop reading device directed requests from ep0
+			
+	TInt err(iDeviceEp0->Stop());
+	if(err != KErrNone)
+		{
+		return ReportError(err);
+		}
+	}
+
+
+void RUsbTestDevice::AcknowledgeRequestReceived()
+	{
+	LOG_FUNC
+	
+	TInt err(iDeviceEp0->Reader().Acknowledge());
+	RDebug::Printf("err = %d",err);
+	if(err != KErrNone)
+		{
+		ReportError(err);
+		}
+	}
+
+
+
+void RUsbTestDevice::ReportError(TInt aCompletionCode)
+	{
+	LOG_FUNC
+	RDebug::Printf("err or aCompletionCode = %d, observer status = %d, KRequestPending = %d",
+			aCompletionCode, iObserverStatus->Int(), KRequestPending);
+	if(*iObserverStatus == KRequestPending)
+		{
+		RDebug::Printf("In complete request");
+		User::RequestComplete(iObserverStatus,aCompletionCode);
+		}
+	}
+	
+
+	}
+