--- /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);
+ }
+ }
+
+
+ }
+