usbmgmt/usbmgr/usbman/server/SRC/CUsbDummyClassController.cpp
changeset 0 c9bc50fca66e
child 15 f92a4f87e424
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/usbman/server/SRC/CUsbDummyClassController.cpp	Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,502 @@
+/*
+* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+* Implements part of UsbMan USB Class Framework.
+*
+*/
+
+/**
+ @file
+*/
+
+#include "CUsbDummyClassController.h"
+#include <usb_std.h>
+#include "inifile.h"
+#include <usb/usblogger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "USBSVR");
+#endif
+
+_LIT(KDummyControllerPanic, "UsbDummyCC"); // must be <=16 chars
+// Panic codes
+enum
+	{
+	// Bad value for the iSynchronicity member.
+	EDummyPanicBadSynchronicity = 0,
+	
+	// Used for environment errors we do not handle.
+	EDummyPanicUnhandledError = 1,
+	
+	// Used for bad iStatus and other state errors.
+	EDummyPanicBadState = 2,
+	
+	// Error reading ini file.
+	EDummyPanicBadIniFile = 3,
+	
+	// We already have our async request active.
+	EDummyPanicAlreadyActive = 4,
+	
+	// We already have a request outstanding from the device class. 
+	EDummyPanicOutstandingRequestFromDevice = 5,
+	
+	// Attempt to call Start() when in illegal state
+	EDummyPanicBadApiCallStart = 6,
+	
+	// Attempt to call Stop() when in illegal state
+	EDummyPanicBadApiCallStop = 7,
+	};
+
+const TInt KDummyClassPriority = 1;
+
+// Keys for reading the ini file.
+_LIT(KStartup, "Startup");
+_LIT(KShutdown, "Shutdown");
+_LIT(KType, "Type");
+_LIT(KTime, "Time");
+_LIT(KError, "Error");
+_LIT(KSync, "sync");
+_LIT(KAsync, "async");
+_LIT(KNever, "never");
+
+CUsbDummyClassController* CUsbDummyClassController::NewL(
+		MUsbClassControllerNotify& aOwner,
+		TUint aIndex)
+/**
+ * Constructs a CUsbDummyClassController object.
+ *
+ * @param aOwner USB Device that owns and manages the class
+ * @param aIndex The index number of the instance
+ * @return Ownership of a new CUsbDummyClassController object
+ */
+	{
+	LOG_STATIC_FUNC_ENTRY
+
+	CUsbDummyClassController* self = new(ELeave) CUsbDummyClassController(aOwner, aIndex);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CUsbDummyClassController* CUsbDummyClassController::NewL(
+	MUsbClassControllerNotify& aOwner, 
+	TUint aIndex, TInt aPriority)
+/**
+ * Constructs a CUsbDummyClassController object.
+ *
+ * @param aOwner USB Device that owns and manages the class
+ * @param aIndex The index number of the instance
+ * @param aPriority The startup priority of the instance
+ * @return Ownership of a new CUsbDummyClassController object
+ */
+ 	{
+	LOG_STATIC_FUNC_ENTRY
+
+ 	CUsbDummyClassController* self = new(ELeave) CUsbDummyClassController(aOwner, aIndex, aPriority);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+ 	}
+ 
+CUsbDummyClassController::CUsbDummyClassController(
+		MUsbClassControllerNotify& aOwner,
+		TUint aIndex)
+/**
+ * Constructor.
+ *
+ * @param aOwner USB Device that owns and manages the class
+ * @param aIndex The index number of the instance
+ */
+ :	CUsbClassControllerBase(aOwner, KDummyClassPriority),
+	iIndex(aIndex)
+	{
+	iState = EUsbServiceIdle; // needs explicit initialisation as non-zero
+	}
+
+CUsbDummyClassController::CUsbDummyClassController(
+		MUsbClassControllerNotify& aOwner,
+		TUint aIndex, TInt aPriority)
+		
+/**
+ * Constructor.
+ *
+ * @param aOwner USB Device that owns and manages the class
+ * @param aIndex The index number of the instance
+ * @param aPriority a startup priority for the class controller
+ */		
+ : 	CUsbClassControllerBase(aOwner, aPriority),
+ 	iIndex(aIndex)
+ 	{
+ 	iState = EUsbServiceIdle; // needs explicit initialisation as non-zero
+ 	}
+		
+void CUsbDummyClassController::ConstructL()
+/**
+ * Method to perform second phase construction.
+ */
+	{
+	LEAVEIFERRORL(iTimer.CreateLocal());
+	}
+
+CUsbDummyClassController::~CUsbDummyClassController()
+/**
+ * Destructor.
+ */
+	{
+	Cancel();
+
+	iTimer.Close();
+	}
+	
+void CUsbDummyClassController::GetBehaviour(CIniFile& aIniFile, 
+											const TDesC& aSection, 
+											TBehaviour& aBehaviour)
+/**
+ * Reads information from the ini file, from a given section, to the given 
+ * behaviour structure.
+ *
+ * @param aIniFile The ini file to read from.
+ * @param aSection The section to reads from.
+ * @param aBehaviour The behaviour struct to read to.
+ */
+	{
+	LOG_FUNC
+#ifdef __FLOG_ACTIVE
+	TBuf8<KMaxName> buf;
+	buf.Copy(aSection);
+	LOGTEXT2(_L8("\taSection = %S"), &buf);
+#endif // __FLOG_ACTIVE
+
+	TPtrC temp;
+	if ( !aIniFile.FindVar(aSection, KType(), temp) )
+		{
+		LOGTEXT2(_L8("\tPANICKING: can't find Type item in section %S"), &aSection);
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadIniFile);
+		}
+	if ( temp == KSync )
+		{
+		aBehaviour.iSynchronicity = ESynchronous;
+		}
+	else if ( temp == KAsync )
+		{
+		aBehaviour.iSynchronicity = EAsynchronous;
+		}
+	else if ( temp == KNever )
+		{
+		aBehaviour.iSynchronicity = ENever;
+		}
+	else
+		{
+		LOGTEXT3(_L8("\tPANICKING: bad Type value (%S) in section %S"), &temp, &aSection);
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadIniFile);
+		}
+	TInt delay;
+	if ( !aIniFile.FindVar(aSection, KTime(), delay) )
+		{
+		LOGTEXT2(_L8("\tPANICKING: can't find Time item in section %S"), &aSection);
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadIniFile);
+		}
+	aBehaviour.iDelay = delay;
+	if ( !aIniFile.FindVar(aSection, KError(), aBehaviour.iErrorCode) )
+		{
+		LOGTEXT2(_L8("\tPANICKING: can't find Error item in section %S"), &aSection);
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadIniFile);
+		}
+	}
+
+void CUsbDummyClassController::DoGetConfigL()
+/**
+ * Reads the config from the ini file.
+ */
+	{
+	LOG_FUNC
+
+	CIniFile* iniFile = CIniFile::NewL(_L("dummy.ini"));
+	CleanupStack::PushL(iniFile);
+	TName section;
+
+	// Read startup behaviour
+	section.Format(_L("%S.%d"), &KStartup(), iIndex);
+	GetBehaviour(*iniFile, section, iStartupBehaviour);
+	// Read shutdown behaviour
+	section.Format(_L("%S.%d"), &KShutdown(), iIndex);
+	GetBehaviour(*iniFile, section, iShutdownBehaviour);
+
+	CleanupStack::PopAndDestroy(iniFile);
+	}
+
+void CUsbDummyClassController::GetConfig()
+/**
+ * Reads the config from the ini file.
+ * Note that this is assumed to succeed. Any failure will break the test and 
+ * it's much cleaner to panic out of the test entirely rather than leave it to 
+ * the user to figure out what's gone wrong.
+ */
+	{
+	LOG_FUNC
+
+	// Always use dummy.ini. The entity setting up the test is responsible for 
+	// copying the correct file to c:\\dummy.ini. The first found 
+	// by FindByDir will be used. TODO: enforce c:\\.
+	TRAPD(err, DoGetConfigL());
+	if ( err != KErrNone )
+		{
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicUnhandledError);
+		}
+	
+	LOGTEXT2(_L8("\tLogging dummy class controller behaviour for instance %d"), iIndex);
+	LOGTEXT2(_L8("\tiStartupBehaviour.iSynchronicity = %d"), iStartupBehaviour.iSynchronicity);
+	LOGTEXT2(_L8("\tiStartupBehaviour.iDelay = %d"), iStartupBehaviour.iDelay.Int());
+	LOGTEXT2(_L8("\tiStartupBehaviour.iErrorCode = %d"), iStartupBehaviour.iErrorCode);
+	LOGTEXT2(_L8("\tiShutdownBehaviour.iSynchronicity = %d"), iShutdownBehaviour.iSynchronicity);
+	LOGTEXT2(_L8("\tiShutdownBehaviour.iDelay = %d"), iShutdownBehaviour.iDelay.Int());
+	LOGTEXT2(_L8("\tiShutdownBehaviour.iErrorCode = %d"), iShutdownBehaviour.iErrorCode);
+	}
+
+void CUsbDummyClassController::Start(TRequestStatus& aStatus)
+/**
+ * Called by UsbMan to start this class.
+ *
+ * @param aStatus Will be completed with success or failure.
+ */
+	{
+	LOG_FUNC
+	
+	//Start() should only be called if the CC is idle or started		
+	__ASSERT_DEBUG((iState == EUsbServiceIdle || iState == EUsbServiceStarted), 
+							_USB_PANIC(KDummyControllerPanic, EDummyPanicBadApiCallStart) );
+
+	// Get config from ini file. Note that can't be done once in ConstructL 
+	// because then, in the case of a CC which doesn't Stop, we'd never be 
+	// able to shut down USBMAN!
+	GetConfig();
+
+	// NB We enforce that the device doesn't re-post requests on us.
+	__ASSERT_DEBUG(!iReportStatus, 
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicOutstandingRequestFromDevice));
+	aStatus = KRequestPending;
+	iReportStatus = &aStatus;
+	
+	iState = EUsbServiceStarting;
+
+	switch ( iStartupBehaviour.iSynchronicity )
+		{
+	case ESynchronous:
+		User::After(iStartupBehaviour.iDelay);
+		iState = EUsbServiceStarted;
+		User::RequestComplete(iReportStatus, iStartupBehaviour.iErrorCode);
+		iReportStatus = NULL;
+		break;
+
+	case EAsynchronous:
+		iTimer.After(iStatus, iStartupBehaviour.iDelay);
+		__ASSERT_DEBUG(!IsActive(), _USB_PANIC(KDummyControllerPanic, EDummyPanicAlreadyActive));		
+		SetActive();
+		break;
+
+	case ENever:
+		// Don't do anything and never complete
+		break;
+
+	default:
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadSynchronicity);
+		break;
+		}
+	}
+
+void CUsbDummyClassController::Stop(TRequestStatus& aStatus)
+/**
+ * Called by UsbMan to stop this class.
+ *
+ * @param aStatus Will be completed with success or failure.
+ */
+	{
+	LOG_FUNC
+		
+	//Stop() should only be called if the CC is Started or Idle
+	__ASSERT_DEBUG((iState == EUsbServiceStarted || iState == EUsbServiceIdle), 
+				_USB_PANIC(KDummyControllerPanic, EDummyPanicBadApiCallStop));
+	
+	// Get config from ini file. Note that can't be done once in ConstructL 
+	// because then, in the case of a CC which doesn't Stop, we'd never be 
+	// able to shutdown USBMAN!
+	GetConfig();
+
+	// NB We enforce that the device doesn't re-post requests on us.
+	__ASSERT_DEBUG(!iReportStatus, 
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicOutstandingRequestFromDevice));
+	aStatus = KRequestPending;
+	iReportStatus = &aStatus;
+
+	iState = EUsbServiceStopping;
+
+	switch ( iShutdownBehaviour.iSynchronicity )
+		{
+	case ESynchronous:
+		User::After(iShutdownBehaviour.iDelay);
+		iState = EUsbServiceIdle;
+		User::RequestComplete(iReportStatus, iShutdownBehaviour.iErrorCode);
+		iReportStatus = NULL;
+		break;
+
+	case EAsynchronous:
+		iTimer.After(iStatus, iShutdownBehaviour.iDelay);
+    	__ASSERT_DEBUG(!IsActive(), _USB_PANIC(KDummyControllerPanic, EDummyPanicAlreadyActive));		
+		SetActive();
+		break;
+
+	case ENever:
+		// Don't do anything and never complete
+		break;
+
+	default:
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadSynchronicity);
+		break;
+		}
+	}
+
+void CUsbDummyClassController::GetDescriptorInfo(TUsbDescriptor& aDescriptorInfo) const
+/**
+ * Returns information about the interfaces supported by this class.
+ *
+ * @param aDescriptorInfo Will be filled in with interface information.
+ */
+	{
+	aDescriptorInfo.iNumInterfaces = 0;
+	aDescriptorInfo.iLength = 0;
+	}
+
+void CUsbDummyClassController::RunL()
+/**
+ * Standard active object RunL. 
+ */
+	{
+	LOGTEXT3(_L8(">>CUsbDummyClassController::RunL [iStatus=%d,iState=%d]"),
+			iStatus.Int(), iState);
+
+	if ( iStatus != KErrNone )
+		{
+		// Panic runtime errors from the timer. We can't ignore them, and 
+		// there's no point trying to code round them. This is part of the 
+		// test framework and if it's failing we want to alert the user 
+		// without faffing around. (It invalidates the test.)
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicUnhandledError);
+		}								  
+
+	__ASSERT_DEBUG(iReportStatus, 
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadState));
+
+	switch ( iState )
+		{
+	case EUsbServiceStarting:
+		// Completion of asynchronous startup...
+		__ASSERT_DEBUG(iStartupBehaviour.iSynchronicity == EAsynchronous, 
+			_USB_PANIC(KDummyControllerPanic, EDummyPanicBadSynchronicity));
+		iState = EUsbServiceStarted;
+		User::RequestComplete(iReportStatus, iStartupBehaviour.iErrorCode);
+		iReportStatus = NULL;
+		break;
+
+	case EUsbServiceStopping:
+		// Completion of asynchronous shutdown...
+		__ASSERT_DEBUG(iShutdownBehaviour.iSynchronicity == EAsynchronous, 
+			_USB_PANIC(KDummyControllerPanic, EDummyPanicBadSynchronicity));
+		iState = EUsbServiceIdle;
+		User::RequestComplete(iReportStatus, iShutdownBehaviour.iErrorCode);
+		iReportStatus = NULL;
+		break;
+
+	case EUsbServiceIdle:
+	case EUsbServiceStarted:
+	default:
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadState);
+		break;
+		}
+
+	LOGTEXT(_L8("<<CUsbDummyClassController::RunL"));
+	}
+
+void CUsbDummyClassController::DoCancel()
+/**
+ * Standard active object cancellation function. 
+ */
+	{
+	LOG_FUNC
+
+	// Note that CActive::Cancel does not call DoCancel unless we are active. 
+	// Therefore we are at this point active. Therefore, we should have 
+	// iReportStatus pointing to something. This is true whether we are in 
+	// our destructor or being cancelled by the device. It is also true that 
+	// (for us to be active at all) our synchronicity should be set to async 
+	// and the timer must have been CreateLocal'd successfully.
+
+	// Cancel may be called in one of the following situations: 
+	// 1/ In our destructor. 
+	// 2/ The device wants to cancel us in the middle of a Start before 
+	// issuing a Stop (or vice versa). Note that the device may cancel us in 
+	// the middle of a Start, then immediately issue another Start.
+	
+	// Cancel our own asynchronous operation.
+	__ASSERT_DEBUG(iTimer.Handle(), 
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadState));
+	iTimer.Cancel();
+
+	// Update our iState. If we're starting, then roll back to idle. If we're 
+	// stopping, role back to started. Nothing else is legal.
+	switch ( iState )
+		{
+	case EUsbServiceStarting:
+		__ASSERT_DEBUG(iStartupBehaviour.iSynchronicity == EAsynchronous, 
+			_USB_PANIC(KDummyControllerPanic, EDummyPanicBadSynchronicity));
+		iState = EUsbServiceIdle;
+		break;
+
+	case EUsbServiceStopping:
+		__ASSERT_DEBUG(iShutdownBehaviour.iSynchronicity == EAsynchronous, 
+			_USB_PANIC(KDummyControllerPanic, EDummyPanicBadSynchronicity));
+		iState = EUsbServiceStarted;
+		break;
+
+	case EUsbServiceIdle:
+	case EUsbServiceStarted:
+	default:
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadState);
+		break;
+		}
+
+	// Complete the client's request.	
+	__ASSERT_DEBUG(iReportStatus, 
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadState));
+	User::RequestComplete(iReportStatus, KErrCancel); 
+	iReportStatus = NULL;
+	}
+
+TInt CUsbDummyClassController::RunError(TInt /*aError*/)
+/**
+ * Standard active object error-handling function. 
+ *
+ * Should return KErrNone to avoid an active scheduler panic. This function
+ * should never be called as there is another mechanism for catching errors.
+ */
+	{
+	__ASSERT_DEBUG(EFalse, 
+		_USB_PANIC(KDummyControllerPanic, EDummyPanicBadState));
+	return KErrNone;
+	}
+
+//
+// End of file