--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbengines/usbwatcher/src/cusbactivepersonalityhandler.cpp Thu Dec 17 09:14:30 2009 +0200
@@ -0,0 +1,557 @@
+/*
+* Copyright (c) 2002-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: This implements UsbActivePersonalityHandler class.
+*
+*/
+
+
+// INCLUDE FILES
+#include <etelmm.h> // for fetching the IMEI code
+#include <mmtsy_names.h> // for RTelServer names
+#include <UsbWatcherInternalCRKeys.h>
+#include <cusbpersonalitynotifier.h>
+#include <cusbpersonalityplugin.h>
+#include <tusbpersonalityparams.h>
+#include <startupdomainpskeys.h> //for global system state
+#include <rusb.h> // for KUsbmanSvrUid
+#include "cusbactivepersonalityhandler.h"
+#include "cusbglobalsystemstateobserver.h"
+
+// CONSTANTS
+// const TInt KSerialNumberLength = 12;
+const TInt KContainerIdLength = 16;
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+// ----------------------------------------------------------------------------
+// C++ default constructor can NOT contain any code, that might leave.
+// ----------------------------------------------------------------------------
+//
+CUsbActivePersonalityHandler::CUsbActivePersonalityHandler(
+ RUsb& aUsbMan, CUsbWatcher& aOwner )
+ : CActive( EPriorityStandard )
+ , iUsbMan( aUsbMan )
+ , iOwner( aOwner )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+// ----------------------------------------------------------------------------
+// Symbian 2nd phase constructor can leave.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::ConstructL()
+ {
+ LOG_FUNC
+
+ iPersonalityNotifier = CUsbPersonalityNotifier::NewL();
+ iPersonalityParams = new ( ELeave ) TUsbPersonalityParams( iUsbMan,
+ *iPersonalityNotifier );
+
+ ConstructUsbSerialNumberL();
+ }
+
+// ----------------------------------------------------------------------------
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+//
+CUsbActivePersonalityHandler* CUsbActivePersonalityHandler::NewL(
+ RUsb& aUsbMan, CUsbWatcher& aOwner )
+ {
+ LOG_FUNC
+
+ CUsbActivePersonalityHandler* self = new ( ELeave )
+ CUsbActivePersonalityHandler( aUsbMan, aOwner );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop(); // pop self
+ return self;
+ }
+
+// Destructor
+CUsbActivePersonalityHandler::~CUsbActivePersonalityHandler()
+ {
+ LOG_FUNC
+
+ Cancel(); // cancel any outstanding requests
+
+ delete iCurrentPersonalityHandler;
+ delete iPersonalityNotifier;
+ delete iPersonalityParams;
+ }
+
+// ----------------------------------------------------------------------------
+// Construct USB serial number. Some of the personalities may need this.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::ConstructUsbSerialNumberL()
+ {
+ LOG_FUNC
+
+ RTelServer telServer;
+ RMobilePhone phone;
+
+ LEAVEIFERROR( telServer.Connect() );
+ CleanupClosePushL( telServer );
+
+ LEAVEIFERROR( telServer.LoadPhoneModule( KMmTsyModuleName ) );
+
+ LEAVEIFERROR( phone.Open( telServer, KMmTsyPhoneName ) );
+ CleanupClosePushL( phone );
+
+ // to store the serial number to be published as the USB device's serial
+ // number, fetch it from telephony server.
+ TRequestStatus status;
+ phone.GetPhoneId( status, iPhoneInfo );
+ User::WaitForRequest( status );
+
+ // make sure that the serial number fulfills USB requirements and then
+ // convert the serial number so that it can be printed to log
+ TLex lex( iPhoneInfo.iSerialNumber );
+ TInt length = iPhoneInfo.iSerialNumber.Length();
+
+ // currently the serial number is used for the USB container ID
+ // the container ID length must be at least 16 bytes
+ // also, even when serial number is not used for the container id
+ // it must be at least 12, see below
+ if( length < KContainerIdLength )
+ {
+ // In GSM, the complete IMEI can used as USB serial number. But in
+ // CDMA, the ESN is too short for a valid Mass Storage serial number
+ // (Mass-Storage and Bulk Only Transport specs both require minimum
+ // 12 byte number), so it is extended with leading zeroes. When
+ // doing this, make sure not to write anything over descriptor's
+ // max length
+ if( iPhoneInfo.iSerialNumber.MaxLength() < KContainerIdLength )
+ {
+ iPhoneInfo.iSerialNumber.SetLength( KContainerIdLength );
+ }
+ while( length < KContainerIdLength )
+ {
+ iPhoneInfo.iSerialNumber.Append( '0' );
+ ++length;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( 2, &telServer );
+ }
+
+// ----------------------------------------------------------------------------
+// Confirm that personality can be loaded.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::ConfirmPersonalityUnload( TRequestStatus&
+ aStatus )
+ {
+ LOG_FUNC
+
+ aStatus = KRequestPending;
+ iRequestStatus = &aStatus;
+
+ if( iState != EUsbPersonalityStarted )
+ {
+ TRequestStatus* status = &iStatus;
+ SetActive();
+ User::RequestComplete( status, KErrGeneral );
+ return;
+ }
+
+ // Cancel all notes before confirmation
+ iPersonalityParams->PersonalityNotifier().CancelAll();
+
+ if( iCurrentPersonalityHandler )
+ {
+ iCurrentPersonalityHandler->ConfirmPersonalityUnload( iStatus );
+ SetActive();
+ }
+ else
+ {
+ TRequestStatus* status = &iStatus;
+ SetActive();
+ User::RequestComplete( status, KErrNone );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Start personality.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::StartPersonality( TInt& aPersonalityId,
+ TInt aAskOnConnectionSetting, TRequestStatus& aStatus )
+ {
+ LOG_FUNC
+
+ LOG2( "PersonalityId = %d, AskOnConnectionSetting = %d", aPersonalityId,
+ aAskOnConnectionSetting );
+
+ // Remove all notes.
+ iPersonalityNotifier->CancelAll();
+
+
+ iPersonalityId = &aPersonalityId;
+ iAskOnConnectionSetting = aAskOnConnectionSetting;
+ aStatus = KRequestPending;
+ iRequestStatus = &aStatus;
+
+ // prepare current personality for start and return
+ if( iCurrentPersonalityHandler )
+ {
+ LOG( "Previous PersonalityHandler not deleted" );
+ User::RequestComplete( iRequestStatus, KErrGeneral );
+ return;
+ }
+
+ TRAPD( ret, ( iCurrentPersonalityHandler = NewPersonalityHandlerL(
+ *iPersonalityId ) ) );
+
+ if( ( ret == KErrNone) && iCurrentPersonalityHandler )
+ {
+ LOG( "PersonalityHandler created" );
+ iCurrentPersonalityHandler->PreparePersonalityStart( iStatus );
+ iState = EUsbPersonalityPrepareStart;
+ SetActive();
+ }
+ else
+ {
+ LOG( "Error: PersonalityHandler create failed" );
+ User::RequestComplete( iRequestStatus, KErrGeneral );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Stop current personality.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::StopPersonality( TRequestStatus& aStatus )
+ {
+ LOG_FUNC
+
+ aStatus = KRequestPending;
+ iRequestStatus = &aStatus;
+
+ iState = EUsbPersonalityPrepareStop;
+
+ // prepare current personality for stop and return
+ if( iCurrentPersonalityHandler )
+ {
+ LOG( "Call PersonalityPlugin to prepare stop" );
+ iCurrentPersonalityHandler->PreparePersonalityStop( iStatus );
+ SetActive();
+ }
+ else
+ {
+ LOG( "No current PersonalityPlugin, return immediately" );
+ TRequestStatus* status = &iStatus;
+ SetActive();
+ User::RequestComplete( status, KErrNone );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Indicates USB device state change to personality when USB is started.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::StateChangeNotify(
+ TUsbDeviceState aStateOld, TUsbDeviceState aStateNew )
+ {
+ LOG_FUNC
+
+ iDeviceState = aStateNew;
+ switch ( aStateNew )
+ {
+ case EUsbDeviceStateAddress:
+ {
+ if( iAskOnConnectionSetting &&
+ ( aStateOld != EUsbDeviceStateSuspended ) &&
+ ( aStateOld != EUsbDeviceStateConfigured )
+ )
+ {
+ iPersonalityParams->PersonalityNotifier().ShowQuery(
+ KCableConnectedNotifierUid, iDummy,
+ iPersonalityPckgBuf);
+ }
+ break;
+ }
+ default:
+ // We do not handle other state here
+ LOG( "DeviceStatechange ignored by ActivePersonalityhandler or EUsbDeviceStateConfigured" );
+ break;
+ }
+
+ if( iCurrentPersonalityHandler )
+ {
+ LOG( "Notifying PersonalityPlugin of the new state" );
+ iCurrentPersonalityHandler->StateChangeNotify( aStateNew );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Standard active object error function. Handle error and complete
+// outstanding request. We must not come here.
+// ----------------------------------------------------------------------------
+//
+TInt CUsbActivePersonalityHandler::RunError( TInt /*aError*/ )
+ {
+ LOG_FUNC
+
+ return KErrNone;
+ }
+
+// ----------------------------------------------------------------------------
+// Executed when iStatus is completed.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::RunL()
+ {
+ LOG_FUNC
+
+ TInt ret = iStatus.Int();
+ if( KErrNone != ret )
+ {
+ LOG1( "ERROR: CUsbActivePersonalityHandler::RunL iStatus = %d", ret );
+ }
+
+ switch( iState )
+ {
+ case EUsbPersonalityIdle:
+ break;
+
+ case EUsbPersonalityPrepareStart:
+ {
+ LOG( "EUsbPersonalityPrepareStart" );
+ // then write the serial number to P&S for USB Manager
+ PublishSerialNumber();
+ iUsbMan.TryStart( *iPersonalityId, iStatus );
+ iState = EUsbPersonalityStartUsb;
+ SetActive();
+ }
+ break;
+
+ case EUsbPersonalityStartUsb:
+ LOG( "EUsbPersonalityStartUsb" );
+ iState = EUsbPersonalityFinishStart;
+ if( iCurrentPersonalityHandler )
+ {
+ iCurrentPersonalityHandler->FinishPersonalityStart( iStatus );
+ SetActive();
+ }
+ else
+ {
+ TRequestStatus* status = &iStatus;
+ SetActive();
+ User::RequestComplete( status, KErrNone );
+ }
+ break;
+
+ case EUsbPersonalityFinishStart:
+ LOG( "EUsbPersonalityFinishStart" );
+ User::RequestComplete( iRequestStatus, ret );
+ iState = EUsbPersonalityStarted;
+ break;
+
+ case EUsbPersonalityPrepareStop:
+ LOG( "EUsbPersonalityPrepareStop" );
+ iUsbMan.TryStop( iStatus );
+ iState = EUsbPersonalityStopUsb;
+ SetActive();
+ break;
+
+ case EUsbPersonalityStopUsb:
+ LOG( "EUsbPersonalityStopUsb" );
+ iState = EUsbPersonalityFinishStop;
+ if( iCurrentPersonalityHandler )
+ {
+ iCurrentPersonalityHandler->FinishPersonalityStop( iStatus );
+ SetActive();
+ }
+ else
+ {
+ TRequestStatus* status = &iStatus;
+ SetActive();
+ User::RequestComplete( status, KErrNone );
+ }
+ break;
+
+ case EUsbPersonalityFinishStop:
+ LOG( "EUsbPersonalityFinishStop" );
+
+ delete iCurrentPersonalityHandler;
+ iCurrentPersonalityHandler = NULL;
+
+ //iAskOnConnectionSetting may be have been set to off
+ if ( iDeviceState == EUsbDeviceStateUndefined )
+ {
+ iPersonalityParams->PersonalityNotifier().CancelQuery(
+ KCableConnectedNotifierUid );
+ }
+ User::RequestComplete( iRequestStatus, ret );
+
+ iState = EUsbPersonalityIdle;
+ break;
+
+ case EUsbPersonalityStarted:
+ // This must unload event. Let's complete.
+ User::RequestComplete( iRequestStatus, ret );
+ break;
+
+ default:
+ LOG( "ERROR: unexpected state" );
+ PANIC( KErrGeneral );
+ break;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Standard active object cancellation function.
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::DoCancel()
+ {
+ LOG_FUNC
+
+ LOG1( "CUsbActivePersonalityHandler::iState = %d", iState );
+ switch( iState )
+ {
+ case EUsbPersonalityFinishStart:
+ {
+ TRequestStatus status;
+
+ iUsbMan.TryStop( status );
+ SetActive();
+ User::WaitForRequest( status );
+ }
+ // Don't break. We need to cancel outstanding request.
+
+ case EUsbPersonalityStarted:
+ case EUsbPersonalityPrepareStop:
+ case EUsbPersonalityFinishStop:
+ if( iCurrentPersonalityHandler )
+ {
+ iCurrentPersonalityHandler->Cancel();
+ }
+ break;
+
+ case EUsbPersonalityStopUsb:
+ iUsbMan.CancelInterest( RUsb::ETryStop );
+ break;
+
+ case EUsbPersonalityStartUsb:
+ iUsbMan.StartCancel();
+ break;
+
+ default:
+ break;
+ }
+
+ if( iCurrentPersonalityHandler && ( iState != EUsbPersonalityStarted ) )
+ {
+ delete iCurrentPersonalityHandler;
+ iCurrentPersonalityHandler = NULL;
+ }
+
+ // if started then this must unload confirmation
+ if( iState != EUsbPersonalityStarted )
+ {
+ iState = EUsbPersonalityIdle;
+ }
+
+ // When cancel happens it means that we can cancel all queries & notes
+ iPersonalityParams->PersonalityNotifier().CancelAll();
+
+ User::RequestComplete( iRequestStatus, KErrCancel );
+ }
+
+// ----------------------------------------------------------------------------
+// Creates and returns a class handler object for the given personality.
+// ----------------------------------------------------------------------------
+//
+CUsbPersonality* CUsbActivePersonalityHandler::NewPersonalityHandlerL(
+ TInt aPersonality )
+ {
+ LOG_FUNC
+
+ TInt personalityCount = iOwner.Personalities().Count();
+
+ for (TInt i = 0; i < personalityCount; i++)
+ {
+ const TUsbSupportedPersonalityInf& pinf = iOwner.Personalities()[i];
+ if( pinf.iPersonalityId == aPersonality )
+ {
+ iPersonalityParams->SetPersonalityId( aPersonality );
+ CUsbPersonalityPlugin* plugin = CUsbPersonalityPlugin::NewL(
+ *iPersonalityParams, pinf.iPersonalityUid );
+ iUseSerialNumber = pinf.iUseSerialNumber;
+ return plugin;
+ }
+ }
+
+ return NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// Publish serial number for USB Manager, if needed.
+// ----------------------------------------------------------------------------
+//
+TInt CUsbActivePersonalityHandler::PublishSerialNumber()
+ {
+ LOG_FUNC
+
+ TInt err = KErrNone;
+
+ if( !iUseSerialNumber && iSerialNumberWritten )
+ {
+ // We are either in test mode or going to start up PC Suite
+ // personality -> delete USB Manager's serial number P&S key
+ // (if necessary)
+ LOG( "Deleting published USB serial number" );
+ err = RProperty::Delete( KUidSystemCategory, KUsbmanSvrUid.iUid );
+ iSerialNumberWritten = EFalse;
+ }
+ else if( iUseSerialNumber && !iSerialNumberWritten )
+ {
+ // to finish, define and write the serial number P&S so that USB
+ // Manager can fetch it
+ _LIT_SECURITY_POLICY_PASS( KAPReadPolicy );
+ _LIT_SECURITY_POLICY_PASS( KAPWritePolicy );
+
+ err = RProperty::Define( KUidSystemCategory, KUsbmanSvrUid.iUid,
+ RProperty::EText, KAPReadPolicy, KAPWritePolicy,
+ KUsbStringDescStringMaxSize );
+
+ if( !err )
+ {
+ err = RProperty::Set( KUidSystemCategory, KUsbmanSvrUid.iUid,
+ iPhoneInfo.iSerialNumber );
+ iSerialNumberWritten = ( err == KErrNone );
+ }
+ }
+
+ LOG1(" ret = %d", err );
+
+ return err;
+ }
+
+// ----------------------------------------------------------------------------
+// Cancel cable connected notifier
+// ----------------------------------------------------------------------------
+//
+void CUsbActivePersonalityHandler::CancelCableConnectedNotifier()
+ {
+ LOG_FUNC
+
+ iPersonalityParams->PersonalityNotifier().CancelQuery(
+ KCableConnectedNotifierUid );
+ }
+
+// End of file