usbclasses/usbphoneasmodem/classcontroller/src/usbmscfileclasscontroller.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 21:13:23 +0200
changeset 2 468cfcb53fd1
parent 0 1e05558e2206
child 3 47c263f7e521
permissions -rw-r--r--
Revision: 201001 Kit: 201003

// 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: 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
    }