usbclasses/usbphoneasmodem/classcontroller/src/usbmscfileclasscontroller.cpp
changeset 0 1e05558e2206
child 2 468cfcb53fd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbclasses/usbphoneasmodem/classcontroller/src/usbmscfileclasscontroller.cpp	Thu Dec 17 09:14:30 2009 +0200
@@ -0,0 +1,441 @@
+// Copyright (c) 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:
+// 
+// 
+
+
+/** 
+ @file
+ Adheres to the UsbMan USB Class Controller API and talks to mass storage 
+ file server
+ */
+
+#include <barsc.h> 
+#include <barsread.h>
+#include <Usb_std.h>
+#include <CUsbClassControllerPlugIn.h>
+#include <usbms.rsg>
+#include <usbmscfileresource.rsg>
+#include <data_caging_path_literals.hrh> 
+#include "usbmscfileclasscontroller.h"
+#include "usbmscfile.h"
+#include "debug.h"
+ 
+// Panic category 
+#ifdef _DEBUG
+_LIT( KMsCcPanicCategory, "UsbMscFileCc" );
+#endif
+
+_LIT( KResourceFileName, "usbmscfileresource.rsc" );
+_LIT( KUsbMsResource, "\\private\\101fe1db\\usbms.rsc" );
+
+/**
+ Panic codes for the USB MSC File Class Controller.
+ */
+enum TMscFileCcPanic
+	{
+	//Class called while in an illegal state
+	EBadApiCall = 0,
+    EUnusedFunction = 1,
+	};
+
+
+static TInt CreateServerProcess()
+    {
+    TRACE_FUNC
+
+    RProcess server;
+    TInt result = server.Create( KMscFileServerFileName, KNullDesC );
+    if ( result != KErrNone )
+        {
+        return  result;
+        }
+
+    TRequestStatus stat;
+
+    server.Rendezvous( stat );
+    if ( stat != KRequestPending )
+        {
+        server.Kill( 0 ); // abort startup
+        }    
+    else
+        {
+        server.Resume(); // logon OK - start the server
+        server.SetPriority( EPriorityForeground );
+        }
+    User::WaitForRequest( stat ); // wait for start or death
+  
+    // we can't use the 'exit reason' if the server panicked as this
+    // is the panic 'reason' and may be '0' which cannot be distinguished
+    // from KErrNone
+    result = ( server.ExitType() == EExitPanic ) ? KErrGeneral : stat.Int();    
+    
+    server.Close();
+
+    return result;
+    }
+
+/**
+ Start MSC File Server
+ */
+static TInt StartServer()
+    {
+    TInt result;
+
+    TFindServer findMscFileServer( KMscFileServerName );
+    TFullName name;
+
+    result = findMscFileServer.Next( name );
+    if ( result != KErrNone )
+        {       
+        result = CreateServerProcess();     
+        }
+
+    TRACE_INFO(( _L( "Server process created: %d" ), result ))
+    return result;
+    }
+
+/**
+ Constructs a CUsbMscFileClassController object
+ 
+ @param	aOwner	USB Device that owns and manages the class
+ @return	A new CUsbMscFileClassController object
+ */
+CUsbMscFileClassController* CUsbMscFileClassController::NewL(
+	MUsbClassControllerNotify& aOwner)
+	{
+	TRACE_FUNC
+
+	CUsbMscFileClassController* r = new (ELeave) CUsbMscFileClassController(aOwner);
+	CleanupStack::PushL(r);
+	r->ConstructL();
+	CleanupStack::Pop();
+	return r;
+	}
+
+/**
+ Destructor
+ */
+CUsbMscFileClassController::~CUsbMscFileClassController()
+	{
+	Cancel();
+	}
+
+/**
+ Constructor.
+ 
+ @param	aOwner	USB Device that owns and manages the class
+ */
+CUsbMscFileClassController::CUsbMscFileClassController(
+	MUsbClassControllerNotify& aOwner )
+	: CUsbClassControllerPlugIn( aOwner, KMsStartupPriority )	
+	{
+	// Intentionally left blank
+	}
+
+/**
+ 2nd Phase Construction.
+ */
+void CUsbMscFileClassController::ConstructL()
+	{
+	TRACE_FUNC
+
+	ReadMassStorageConfigL();
+	}
+
+/**
+ Called by UsbMan when it wants to start the mass storage class. 
+ 
+ @param aStatus The caller's request status, filled in with an error code
+ */
+void CUsbMscFileClassController::Start( TRequestStatus& aStatus )
+	{
+	TRACE_FUNC_ENTRY
+	
+	// The service state should always be idle when this function is called 
+	// (guaranteed by CUsbSession).
+	__ASSERT_DEBUG( iState == EUsbServiceIdle, 
+	        User::Panic( KMsCcPanicCategory, EBadApiCall ) );
+
+	TRequestStatus* reportStatus = &aStatus;
+
+	iState = EUsbServiceStarting;
+
+    TInt ret = StartServer();
+    if ( ret != KErrNone )
+        {
+		iState = EUsbServiceIdle;
+		User::RequestComplete( reportStatus, ret );
+        TRACE_ERROR(( _L( "Error %d Can't start server." ), ret ))
+        return;
+        }
+    
+    TRAP( ret, SetupUnitsL() );
+    if (ret != KErrNone)
+        {
+		iState = EUsbServiceIdle;
+		User::RequestComplete( reportStatus, ret );
+        TRACE_ERROR(( _L( "Error %d in SetupUnitsL." ), ret ))
+        return;
+        }
+
+
+	// Connect to USB Mass Storage server
+	ret = iMscFile.Connect();
+
+	if ( ret != KErrNone )
+		{
+		iState = EUsbServiceIdle;
+		User::RequestComplete( reportStatus, ret );
+		TRACE_ERROR(( _L( "Error %d connecting to msc file server" ), ret ))
+		return;
+		}
+
+	// StartL mass storage device
+	ret = iMscFile.Start( iMsConfig );
+
+	if (ret != KErrNone)
+		{
+		iState = EUsbServiceIdle;
+		User::RequestComplete( reportStatus, ret );
+		TRACE_ERROR(( _L( "Error %d starting msc file server" ), ret ))
+		return;
+		}
+
+	iState = EUsbServiceStarted;
+
+	User::RequestComplete(reportStatus, KErrNone);
+	TRACE_FUNC_EXIT
+	}
+
+/**
+ Called by UsbMan when it wants to stop the USB ACM class.
+ 
+ @param aStatus KErrNone on success or a system wide error code
+ */
+void CUsbMscFileClassController::Stop( TRequestStatus& aStatus )
+	{
+	TRACE_FUNC_ENTRY
+	
+	// The service state should always be started when this function is called
+	// (guaranteed by CUsbSession)
+	__ASSERT_DEBUG( iState == EUsbServiceStarted, 
+	                User::Panic( KMsCcPanicCategory, EBadApiCall ) );
+
+	TRequestStatus* reportStatus = &aStatus;
+	
+	TInt ret = iMscFile.Stop();
+	
+	if ( ret != KErrNone )
+		{
+		iState = EUsbServiceStarted;
+		User::RequestComplete( reportStatus, ret );
+		TRACE_ERROR(( _L( "Error %d stopping msc file server" ), ret ))
+		return;
+		}	
+
+	ret = iMscFile.Shutdown();
+	if ( ret != KErrNone )
+		{
+		User::RequestComplete( reportStatus, ret );
+		TRACE_ERROR(( _L( "Error %d stopping msc file server" ), ret ))
+		}	
+  else
+	  {
+		User::RequestComplete( reportStatus, KErrNone );
+	  }    
+	iMscFile.Close();
+	
+	iState = EUsbServiceIdle;
+	TRACE_FUNC_EXIT
+	}
+
+/**
+ Gets information about the descriptor which this class provides. Never called
+ by usbMan.
+ 
+ @param aDescriptorInfo Descriptor info structure filled in by this function
+ */
+void CUsbMscFileClassController::GetDescriptorInfo(TUsbDescriptor& /*aDescriptorInfo*/) const
+	{
+	__ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction));
+	}
+
+/**
+ Standard active object RunL. Never called because this class has no
+ asynchronous requests.
+ */
+void CUsbMscFileClassController::RunL()
+	{
+	__ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction) );
+	}
+
+/**
+ Standard active object cancellation function. Never called because this
+ class has no asynchronous requests.
+ */
+void CUsbMscFileClassController::DoCancel()
+	{
+	__ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction) );
+	}
+
+/**
+ Standard active object error function. Never called because this class has
+ no asynchronous requests, and hence its RunL is never called.
+ 
+ @param aError The error code (unused)
+ @return Always KErrNone to avoid an active scheduler panic
+ */
+TInt CUsbMscFileClassController::RunError(TInt /*aError*/)
+	{
+	__ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction) );
+	return KErrNone;
+	}
+
+/**
+ Read mass storage configuration info from the resource file
+ */
+void CUsbMscFileClassController::ReadMassStorageConfigL()
+	{
+	TRACE_FUNC_ENTRY
+
+	// Try to connect to file server
+	RFs fs;
+	LEAVE_IF_ERROR( fs.Connect() );
+	CleanupClosePushL( fs );
+
+    TFileName fileName;
+    const TDriveNumber KResourceDrive = EDriveZ;
+    TDriveUnit driveUnit( KResourceDrive );
+    TDriveName drive = driveUnit.Name();
+    fileName.Insert( 0, drive );
+
+    fileName += KUsbMsResource;
+
+	RResourceFile resource;
+	TRAPD( err, resource.OpenL( fs, fileName ) );
+
+	if ( err != KErrNone )
+		{
+		TRACE_ERROR(( _L( "Error %d opening resource file" ), err ))
+		CleanupStack::PopAndDestroy( &fs );
+		return;
+		}
+
+	CleanupClosePushL( resource );
+
+	resource.ConfirmSignatureL( KUsbMsResourceVersion );
+
+	HBufC8* msConfigBuf = 0;
+	TRAPD( ret, msConfigBuf = resource.AllocReadL( USBMS_CONFIG ) );
+	if ( ret != KErrNone )
+		{
+		TRACE_ERROR(( _L( "Error %d opening mass storage config" ), ret ))
+		CleanupStack::PopAndDestroy(2, &fs); 
+		return;
+		}
+	CleanupStack::PushL( msConfigBuf );
+	
+	// The format of the USB resource structure is:
+	
+	/* 	
+	 * 	STRUCT USBMASSSTORAGE_CONFIG
+	 *	{
+	 *	LTEXT	vendorId;           // no more than 8 characters
+	 *	LTEXT	productId;          // no more than 16 characters
+	 *	LTEXT	productRev;        	// no more than 4 characters
+	 *	};
+	 */
+	 
+	// Note that the resource must be read in this order!
+	
+	TResourceReader reader;
+	reader.SetBuffer( msConfigBuf );
+
+	TPtrC	vendorId		= reader.ReadTPtrC();
+	TPtrC	productId		= reader.ReadTPtrC();
+	TPtrC	productRev		= reader.ReadTPtrC();
+	
+	// populate iMsConfig, truncate if exceeding limit
+	ConfigItem( vendorId, iMsConfig.iVendorId, 8 );
+	ConfigItem( productId, iMsConfig.iProductId, 16 );
+	ConfigItem( productRev, iMsConfig.iProductRev, 4 );
+	
+	// Debugging
+	TRACE_INFO(( _L( "vendorId = %s" ),   &vendorId ))
+	TRACE_INFO(( _L( "productId = %s" ),  &productId ))
+	TRACE_INFO(( _L( "productRev = %s" ), &productRev ))
+		
+	CleanupStack::PopAndDestroy( 3, &fs ); // msConfigBuf, resource, fs
+	TRACE_FUNC_EXIT
+	}
+	
+/**
+ Utility. Copies the data from TPtr to TBuf and checks data length 
+ to make sure the source does not exceed the capacity of the target
+ */
+ void CUsbMscFileClassController::ConfigItem( const TPtrC& source, 
+                                              TDes& target, 
+                                              TInt maxLength )
+ 	{
+ 	if ( source.Length() < maxLength )
+ 		{
+ 		maxLength = source.Length();
+ 		}
+ 		
+ 	target.Copy( source.Ptr(), maxLength );	 	
+ 	}
+
+void CUsbMscFileClassController::SetupUnitsL()
+    {
+    RFs fs;
+    RUsbMscFile mscFile;
+    
+    LEAVE_IF_ERROR( mscFile.Connect() );
+    CleanupClosePushL( mscFile );
+    LEAVE_IF_ERROR( fs.Connect() );
+    CleanupClosePushL( fs );
+
+    TFileName fileName;
+    const TDriveNumber KStoreDrive = EDriveZ;
+    TDriveUnit driveUnit( KStoreDrive );
+    TDriveName drive = driveUnit.Name();
+    fileName.Insert( 0, drive );
+
+    fileName += KDC_APP_RESOURCE_DIR; // From data_caging_path_literals.hrh
+    fileName += KResourceFileName;
+
+    RResourceFile resourceFile;
+    CleanupClosePushL( resourceFile );
+    resourceFile.OpenL( fs, fileName );
+    resourceFile.ConfirmSignatureL();
+
+    HBufC8* buf8 = resourceFile.AllocReadLC( R_USBMSCFILE_IMAGE_PATHS );
+    
+    TResourceReader reader;
+    reader.SetBuffer( buf8 );
+    
+    TInt count = reader.ReadInt16(); 
+
+    while ( count-- )
+        {
+        TInt protocol = reader.ReadUint16();
+        TInt lun =      reader.ReadUint16();
+        HBufC* path =   reader.ReadHBufCL();
+        CleanupStack::PushL( path );
+        LEAVE_IF_ERROR( mscFile.SetupLogicalUnit( *path, protocol, lun ) );
+        CleanupStack::PopAndDestroy( path );
+        }
+    CleanupStack::PopAndDestroy( 4 ); // mscFile, fs, resourceFile, buf8
+    }