diff -r 7858bc6ead78 -r 9d8b04ca6939 usbengines/usbwatcher/src/cusbactivepersonalityhandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbengines/usbwatcher/src/cusbactivepersonalityhandler.cpp Fri Jun 04 10:27:39 2010 +0100 @@ -0,0 +1,610 @@ +/* +* Copyright (c) 2002-2010 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 // for fetching the IMEI code +#include // for RTelServer names +#include +#include +#include +#include +#include //for global system state +#include "cusbactivepersonalityhandler.h" +#include "cusbglobalsystemstateobserver.h" +#include + +// CONSTANTS +const TInt KSerialNumberLength = 12; + +const TUid KUsbmanSvrUid = {0x101fe1db}; + +// ============================ 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 ) + , isFailureCleanup( EFalse ) + { + 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(); + + if( length < KSerialNumberLength ) + { + // In GSM, the complete IMEI can be 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 trailing zeroes. When doing this, make sure + // not to write anything over descriptor's max length + if( iPhoneInfo.iSerialNumber.MaxLength() < KSerialNumberLength ) + { + iPhoneInfo.iSerialNumber.SetLength( KSerialNumberLength ); + } + while( length < KSerialNumberLength ) + { + 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; + isFailureCleanup = EFalse; + 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; + isFailureCleanup = EFalse; + + // 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; + } + case EUsbDeviceStateUndefined: + { + iPersonalityNotifier->CancelQuery(KQueriesNotifier); + 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 + + LOG2("Returned error: %d, iState: %d", aError, iState); + + switch ( aError ) + { + case KErrNoMemory: + iQueryParams().iQuery = EUSBNotEnoughRam; + iPersonalityParams->PersonalityNotifier().ShowQuery(KQueriesNotifier, + iQueryParams, iDummyBuf); + break; + case KErrDiskFull: + iQueryParams().iQuery = EUSBDiskFull; + iPersonalityParams->PersonalityNotifier().ShowQuery(KQueriesNotifier, + iQueryParams, iDummyBuf); + break; + default: + LOG( "Ignored" ); + } + + //only handle error when TryStart fails now + //clean up work to be done in the personality + if (iState == EUsbPersonalityStartUsb) + { + iState = EUsbPersonalityPrepareStop; + isFailureCleanup = ETrue; + + // prepare current personality for stop and return + if( iCurrentPersonalityHandler ) + { + LOG( "Call PersonalityPlugin to prepare stop" ); + iCurrentPersonalityHandler->PreparePersonalityStop( iStatus ); + SetActive(); + } + else + { + LOG( "No current PersonalityPlugin" ); + } + + //complete StartPersonality with aError + User::RequestComplete( iRequestStatus, aError ); + } + else + { + LOG( "Ignore error in other states" ); + } + + return KErrNone; + } + +// ---------------------------------------------------------------------------- +// Executed when iStatus is completed. +// ---------------------------------------------------------------------------- +// +void CUsbActivePersonalityHandler::RunL() + { + LOG_FUNC + + TInt ret = iStatus.Int(); + + LOG2( "CUsbActivePersonalityHandler::RunL iStatus = %d, iState = %d", ret, iState ); + + 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: + LEAVEIFERROR( ret ); + 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 ); + } + //the request should be completed with error code in RunError if failed + if ( !isFailureCleanup ) + { + 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