diff -r 000000000000 -r 4e1aa6a622a0 resourcemgmt/hwresourcesmgr/server/src/HWRMVibraService.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/resourcemgmt/hwresourcesmgr/server/src/HWRMVibraService.cpp Tue Feb 02 00:53:00 2010 +0200 @@ -0,0 +1,1288 @@ +// Copyright (c) 2006-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: +// + + + + +// INCLUDE FILES +#include "HWRMServer.h" +#include "HWRMVibraClientServer.h" +#include "HWRMService.h" +#include "HWRMVibraService.h" +#include "HWRMVibraCommands.h" +#include "HWRMPluginHandler.h" +#include "HWRMtrace.h" +#include "HWRMVibraCommonData.h" +#include "HWRMVibra.h" +#include "HWRMReservationHandler.h" +#include "HWRMPrivateCRKeys.h" +#include "HWRMDomainPSKeys.h" +#include "HWRMPrivatePSKeys.h" +#include "HWRMVibraCommonService.h" + + + +// EXTERNAL DATA STRUCTURES +// None + +// EXTERNAL FUNCTION PROTOTYPES +// None + +// CONSTANTS +// None + +// MACROS +// None + +// LOCAL CONSTANTS AND MACROS +_LIT( KPanicCategory, "HWRMVibraService" ); + +const TInt KHWRMVibraMaxDurationInMicroseconds = KHWRMVibraMaxDuration * 1000; + +const TInt KHWRMVibraTimerID = KMaxTInt; +const TInt KHWRMVibraNoTimer = KMinTInt; + + +// MODULE DATA STRUCTURES +// None + +// LOCAL FUNCTION PROTOTYPES +// None + +// FORWARD DECLARATIONS +// None + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::CHWRMVibraService +// C++ constructor +// ----------------------------------------------------------------------------- +// +CHWRMVibraService::CHWRMVibraService(CHWRMVibraCommonService& aCommonService, + CHWRMVibraCommonData& aVibraCommonData, + TBool aPrivilegedClient) + : iVibraCommonData(aVibraCommonData), + iPrivilegedClient(aPrivilegedClient), + iStateSetAfterReservation(EFalse), + iCommonService(aCommonService), + iSid(0), + iActiveTimerId(KHWRMVibraTimerID) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::CHWRMVibraService()" ) ); + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::CHWRMVibraService - return" ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ConstructL(CHWRMPluginHandler* aPluginHandler, + CHWRMReservationHandler* aReservationHandler) + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::ConstructL(0x%x)" ), aPluginHandler ); + + BaseConstructL(aPluginHandler, aReservationHandler); + + // Create vibra timer with special identifier. + iVibraTimer = CHWRMGenericTimer::NewL(*this, iVibraCommonData.MaximumOnTime(), KHWRMVibraTimerID); + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ConstructL - return " ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CHWRMVibraService* CHWRMVibraService::NewL(CHWRMPluginHandler* aPluginHandler, + CHWRMReservationHandler* aReservationHandler, + CHWRMVibraCommonService& aCommonService, + CHWRMVibraCommonData& aVibraCommonData, + TBool aPrivilegedClient) + { + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::NewL(0x%x, aPrivilegedClient: 0x%x)" ), aPluginHandler, aPrivilegedClient ); + + CHWRMVibraService* self = new( ELeave ) CHWRMVibraService(aCommonService, aVibraCommonData, aPrivilegedClient); + + CleanupStack::PushL( self ); + self->ConstructL(aPluginHandler, aReservationHandler); + CleanupStack::Pop(); + + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::NewL - return 0x%x" ), self ); + + return self; + } + +// --------------------------------------------------------- +// Destructor +// --------------------------------------------------------- +// +CHWRMVibraService::~CHWRMVibraService() + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::~CHWRMVibraService()" ) ); + + // Cleanup vibra just in case regular cleanup failed + CleanupVibra(); + + // Delete timer + if (iVibraTimer) + { + iVibraTimer->Cancel(); + delete iVibraTimer; + } + + ReleasePulseData(); + + // Base class cleanup + BaseDestruct(); + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::~CHWRMVibraService - return" ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ReleasePulseData +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ReleasePulseData() + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::ReleasePulseData(), count %d" ), iPulseData.Count() ); + + iPulseData.ResetAndDestroy(); + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ReleasePulseData - return" ) ); + } + + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::CleanupVibra +// Cleans up vibra. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::CleanupVibra() + { + if ( !iCleanupDone ) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::CleanupVibra()" ) ); + TInt unreserved(0x0); + + // If still reserved, release + if ( iReserved ) + { + unreserved = iReservationHandler->Release(this, KHWRMAllSubResources); + iReserved = EFalse; + iSuspended = EFalse; + } + else + { + unreserved = iReservationHandler->GetUnreservedTargets(); + } + + COMPONENT_TRACE3(_L("HWRM Server - CHWRMVibraService::CleanupVibra - Vibra status: %d, reservation status: %d"), iLastStatus, unreserved ); + + // If this session has set vibra to vibrate and vibra is unreserved, stop it. + if ( unreserved && iLastStatus == CHWRMVibra::EVibraStatusOn ) + { + RMessage2 dummy; // Use dummy to avoid adaptation returned error messages failing cleanup + TRAPD(err, StopVibraL(dummy, EFalse, ETrue)); + if ( err != KErrNone ) + { + COMPONENT_TRACE2(_L("HWRM Server - CHWRMVibraService::CleanupVibra - Stopping vibra failed: %d"), err ); + } + else + { + // Since there will be no ProcessResponse for this one, publish the status now + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusStopped, iPrivilegedClient); + } + } + + // Make sure client requests get cleared if not via StopVibraL + if( iCommonService.HasData( this ) ) + { + iCommonService.ResetClientData( this ); + } + + iCleanupDone = ETrue; + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::CleanupVibra - return" ) ); + } + else + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::CleanupVibra - Already cleaned up" ) ); + } + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ForceVibraStop +// Stops vibra. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ForceVibraStop() + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ForceVibraStop()" ) ); + + RMessage2 dummy; + TRAP_IGNORE(StopVibraL(dummy, ETrue)); + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ForceVibraStop - return" ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ExecuteMessageL +// Handles Vibra requests. +// ----------------------------------------------------------------------------- +// +TBool CHWRMVibraService::ExecuteMessageL( const RMessage2& aMessage ) + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::ExecuteMessageL(0x%x)" ), aMessage.Function() ); + + __ASSERT_ALWAYS(iPluginHandler, User::Panic(KPanicCategory, EPanicBadHandle)); + __ASSERT_ALWAYS(iReservationHandler, User::Panic(KPanicCategory, EPanicBadHandle)); + + if ( aMessage.IsNull() ) + { + User::Leave(KErrBadHandle); + } + + // All messages are by default asynchronous because of the nature of the plugin API + TBool completeMessage(EFalse); + TInt function( aMessage.Function() ); + + // Retrieve client sid + iSid = aMessage.SecureId(); + + switch ( function ) + { + case EHWRMStartVibraDefaultIntensity: + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMStartVibraDefaultIntensity") ); + + StartVibraL( aMessage.Int0() * 1000, KUseDefaultIntensity, aMessage); + + break; + } + case EHWRMStartVibra: + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMStartVibra") ); + + StartVibraL(aMessage.Int0() * 1000, aMessage.Int1(), aMessage); + + break; + } + case EHWRMPulseVibraDefault: + case EHWRMPulseVibraDefaultIntensity: + case EHWRMPulseVibra: + { + // First of all check whether pulse request allowed by this client. + if ( !iCommonService.VibraPulseAllowed( aMessage.SecureId() ) ) + { + User::Leave(KErrAccessDenied); + } + + TInt duration( iVibraCommonData.FeedbackDefaultDuration() * 1000 ); + TInt intensity( iVibraCommonData.FeedbackDefaultIntensity() ); + + if( function == EHWRMPulseVibraDefault ) + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMPulseVibraDefault") ); + } + else if( function == EHWRMPulseVibraDefaultIntensity ) + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMPulseVibraDefaultIntensity") ); + duration = aMessage.Int0() * 1000; + } + else + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMPulseVibra") ); + duration = aMessage.Int0() * 1000; + intensity = aMessage.Int1(); + } + + COMPONENT_TRACE2(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - pulse supported %d"), + iVibraCommonData.FeedbackPulseSupported() ); + + // If there is active reservation and vibration ongoing by a higher priority client, + // pulse request is not allowed. In all other circumstances either pulse or start + // command is sent to plugin. + if ( iReservationHandler->IsReserved(this, KHWRMAllSubResources) && + iCommonService.ExecutingPriorityHigher( aMessage.SecureId() ) ) + { + User::Leave(KErrInUse); + } + + if( iVibraCommonData.FeedbackPulseSupported() ) + { + // It is plugin or underlying software responsibility to generate pulse start/stop + // and continue ongoing vibration if such exists. + PulseVibraL( duration, intensity, aMessage); + } + else + { + // Request another vibration by lefting current timer if such exist intact + // and creating new timer for this pulse request. + StartVibraL( duration, intensity, aMessage, EFalse, ETrue); + } + + break; + } + case EHWRMStopVibra: + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMStopVibra") ); + + StopVibraL(aMessage); + break; + } + case EHWRMReserveVibra: + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMReserveVibra") ); + + // Reserve whole vibra. If returned mask is non-zero, reservation was done in suspended mode. + iSuspended = (iReservationHandler->ReserveL(aMessage, aMessage.Int1(), this, KHWRMAllSubResources)); + + iReserved = ETrue; + + iStateSetAfterReservation = EFalse; + + // Restore previously stored state if restore was specified. + // Errors are trapped as reservation itself was successful. + if ( aMessage.Int0() ) + { + TInt err(KErrNone); + RMessage2 dummy; // Use dummy to avoid adaptation returned error messages failing reservation. + + if ( iFrozenStatus == CHWRMVibra::EVibraStatusOn ) + { + TRAP(err, StartVibraL(iFrozenTime, iFrozenIntensity, dummy)); + } + else + { + TRAP(err, StopVibraL(dummy)); + } + } + + completeMessage = ETrue; // Complete needed, as dummy used. + break; + } + case EHWRMReleaseVibra: + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMReleaseVibra") ); + + // If a "Leave" is introduced, consideration must be given to the corresponding + // client side side code which requested this action. In particular, ensure that + // the client-side caller doesn't set its "iReserved" flag to false without + // checking the result of the Release command. + + // Release whole vibra. + TInt unreserved = iReservationHandler->Release(this, KHWRMAllSubResources); + + iReserved = EFalse; + + // Clear suspended flag + iSuspended = EFalse; + + // Freeze state + iFrozenTime = iVibraTimer->Freeze(); + iFrozenStatus = iLastStatus; + iFrozenIntensity = iLastIntensity; + + // Restore base state if no more reservations for vibra. + // Errors are trapped as release itself was successful. + if ( unreserved ) + { + RMessage2 dummy; // Use dummy to avoid adaptation returned error messages failing release. + TRAP_IGNORE(StopVibraL(dummy)); + } + + completeMessage = ETrue; // Complete needed, as dummy used. + break; + } + case EHWRMCleanupVibra: + { + COMPONENT_TRACE1(_L("HWRM Server - CHWRMVibraService::ExecuteMessageL - EHWRMCleanupVibra") ); + + CleanupVibra(); + + completeMessage = ETrue; // Complete needed, as dummy used in CleanupVibra. + break; + } + // Cannot identify the message, panic the client + default: + { + CHWRMServer::PanicClient(aMessage, EPanicIllegalFunction); + break; + } + } + + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::ExecuteMessageL - return 0x%x" ), completeMessage ); + + return completeMessage; + + } +// ----------------------------------------------------------------------------- +// CHWRMVibraService::StartVibraL +// Starts vibra for duration with specified intensity. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::StartVibraL(const TTimeIntervalMicroSeconds32& aDuration, + TInt aIntensity, + const RMessage2& aMessage, + TBool aSetTimer, + TBool aPulse) + { + + COMPONENT_TRACE5(_L( "HWRM Server - CHWRMVibraService::StartVibraL(%d, %d, %d, %d)" ), + aDuration.Int(), aIntensity, aSetTimer, aPulse ); + + + __ASSERT_ALWAYS(iPluginHandler, User::Panic(KPanicCategory, EPanicBadHandle)); + + // Duration must not be negative. + if ( aDuration.Int() < 0 || aDuration.Int() > KHWRMVibraMaxDurationInMicroseconds ) + { + User::Leave(KErrArgument); + } + + // Check vibra/feedback profile settings if not privileged client. + // If not pulse request, vibra must be on. If pulse request, feedback must be on. + if ( !iPrivilegedClient && + ( ( !aPulse && (iVibraCommonData.VibraState() != CHWRMVibra::EVibraModeON ) ) || + ( aPulse && (iVibraCommonData.VibraFeedbackState() != CHWRMVibra::EVibraFeedbackModeON) ) ) ) + { + // Stop vibra if it needs shutdown. + if ( iLastStatus == CHWRMVibra::EVibraStatusOn ) + { + StopVibraL(aMessage); + } + User::Leave(KErrAccessDenied); + } + + // Check if vibra is cooling off or feedback should be prevented + if ( iVibraCommonData.VibraLocked() || (aPulse && VibraPulseBlocked()) ) + { + User::Leave(KErrLocked); + } + + // Check if vibra is blocked (aPulse means no feedback request) + if ( !aPulse && + iVibraCommonData.VibraBlocked() && + iVibraCommonData.VibraBlocked( KHWRMInternalSettingsChargerBlockVibra ) ) + { + User::Leave(KErrLocked); + } + + + // Check intensity validity + if ( aIntensity != KUseDefaultIntensity && (aIntensity < KHWRMVibraMinIntensity || aIntensity > KHWRMVibraMaxIntensity) ) + { + User::Leave(KErrArgument); + } + + // Check intensity validity for pulse requests + if ( aPulse && (aIntensity < KHWRMVibraMinPulseIntensity || aIntensity > KHWRMVibraMaxIntensity) ) + { + User::Leave(KErrArgument); + } + + // Call plugins + if ( aIntensity == 0 ) + { + // Stop vibra, if intensity is zero + StopVibraL(aMessage); + } + else + { + // Start timers, if so specified + // This is because when restoring last state, existing timer should be left intact. + // Vibra timer is left intact also if pulse requested because new timer is setup. + if ( aSetTimer && !aPulse ) + { + iVibraTimer->Set(aDuration); + iActiveTimerId = KHWRMVibraTimerID; + } + + if ( aPulse ) + { + // Create new timer with ascending identifier. + TInt count( iPulseData.Count() ); + CHWRMGenericTimer* timer = + CHWRMGenericTimer::NewL(*this, iVibraCommonData.MaximumOnTime(), count ); + iActiveTimerId = count; + CPulseData* pulseData = CPulseData::NewL(*timer, iLastIntensity, aIntensity, iActiveTimerId ); + CleanupStack::PushL( pulseData ); + iPulseData.AppendL( pulseData ); + CleanupStack::Pop( pulseData ); + iPulseData[count]->Timer().Set(aDuration); + } + + // complete message if suspended, as there will not be ProcessResponseL + if ( iSuspended && aMessage.Handle() ) + { + aMessage.Complete(KErrNone); + } + + // Call plugin if not suspended + if ( !iSuspended ) + { + // Check reservation if not pulse request (pulse is blocked earlier if priority + // of this client is lower than reserving client). + if ( !aPulse && iReservationHandler->IsReserved(this, KHWRMAllSubResources) ) + { + User::Leave(KErrInUse); + } + + // Create new data (TransId is updated later, commandId is not important) + THWRMPluginRequestData* data = new (ELeave) THWRMPluginRequestData(aMessage, 0, 0, EFalse); + CleanupStack::PushL( data ); + + if ( aIntensity == KUseDefaultIntensity ) + { + // No data, pass empty descriptor + TBuf8<1> emptyDes; + data->iTransId = iPluginHandler->ProcessCommandL(HWRMVibraCommand::EStartVibraWithDefaultSettingsCmdId, emptyDes, this); + } + else + { + HWRMVibraCommand::TStartVibraCmdDataPackage dataPckg(aIntensity); + data->iTransId = iPluginHandler->ProcessCommandL(HWRMVibraCommand::EStartVibraCmdId, dataPckg, this); + } + + // data still needed, do not destroy, just pop + CleanupStack::Pop( data ); + + // Add data to list + iTransactionList->AddTransaction( data ); + + // Assign request data for common vibra service + TVibraClientData clientData( this, iSid, aIntensity ); + // Control of overlapping pulses/normal vibration requests is in hands of HWRM, + // when pulse length is configured to be handled by HWRM. That is why + // client data must be set to common vibra service. + iCommonService.SetClientData( clientData ); + + + iStateSetAfterReservation = ETrue; + } + } + // Store the latest status in case vibra gets suspended before next plugin call. + iLastStatus = CHWRMVibra::EVibraStatusOn; + iLastIntensity = aIntensity; + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::StartVibraL - return" ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::VibraPulseBlocked +// Checks whether vibra pulse should be blocked. +// ----------------------------------------------------------------------------- +// +TBool CHWRMVibraService::VibraPulseBlocked() + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::VibraPulseBlocked" ) ); + TBool blocked( EFalse ); + + // Check whether vibra cooling off should prevent feedback + if ( iVibraCommonData.VibraLocked() && + iVibraCommonData.VibraBlocked( KHWRMInternalSettingsCoolOffBlockFeedback ) ) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::VibraPulseBlocked - blocked by cool-off" )); + blocked = ETrue; + } + + // Check if vibra is blocked and whether it should prevent feedback + if ( (iVibraCommonData.VibraBlocked() & KHWRMAccessoryVibraBlocked) && + iVibraCommonData.VibraBlocked( KHWRMInternalSettingsAccessoryBlockFeedback ) ) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::VibraPulseBlocked - blocked by accessory" ) ); + blocked = ETrue; + } + if ( (iVibraCommonData.VibraBlocked() & KHWRMInternalVibraBlocked) && + iVibraCommonData.VibraBlocked( KHWRMInternalSettingsChargerBlockFeedback ) ) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::VibraPulseBlocked - blocked by charger" ) ); + blocked = ETrue; + } + + return blocked; + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::PulseVibraL +// Requests vibra pulse with specified intensity and duration. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::PulseVibraL(const TTimeIntervalMicroSeconds32& aDuration, + TInt aIntensity, + const RMessage2& aMessage, + TBool /* aSetTimer */) + { + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::PulseVibraL(%d, %d)" ), aDuration.Int(), aIntensity ); + + __ASSERT_ALWAYS(iPluginHandler, User::Panic(KPanicCategory, EPanicBadHandle)); + + // Duration must not be negative. + if ( aDuration.Int() < 0 || aDuration.Int() > KHWRMVibraMaxDurationInMicroseconds ) + { + User::Leave(KErrArgument); + } + + // Check intensity validity + if ( aIntensity < KHWRMVibraMinPulseIntensity || aIntensity > KHWRMVibraMaxIntensity ) + { + User::Leave(KErrArgument); + } + + if( VibraPulseBlocked() ) + { + User::Leave(KErrLocked); + } + + // Check vibra profile setting if not privileged client + if ( !iPrivilegedClient && iVibraCommonData.VibraFeedbackState() != CHWRMVibra::EVibraFeedbackModeON ) + { + // Stop vibra if it needs shutdown. + if ( iLastStatus == CHWRMVibra::EVibraStatusOn ) + { + StopVibraL(aMessage); + } + User::Leave(KErrAccessDenied); + } + + // Finally before sending pulse-command to plugin check that this client + // has higher priority than last client requested vibration. + + // Call plugins + if ( aIntensity == 0 ) + { + // Stop vibra, if intensity is zero + StopVibraL(aMessage); + } + else + { + // There is no timer for real pulse requests, because low level + // implementation must stop the vibra after specified duration. + // This will however result in vibra status not being updated. + iActiveTimerId = KHWRMVibraNoTimer; + + // Complete message if suspended, as there will not be ProcessResponseL + if ( iSuspended && aMessage.Handle() ) + { + aMessage.Complete(KErrNone); + } + + // Call plugin if not suspended + if ( !iSuspended ) + { + // Create new data (TransId is updated later, commandId is not important) + THWRMPluginRequestData* data = new (ELeave) THWRMPluginRequestData(aMessage, 0, 0, EFalse); + CleanupStack::PushL( data ); + HWRMVibraCommand::TVibraData vibraData; + vibraData.iIntensity = aIntensity; + vibraData.iDuration = aDuration.Int() / 1000; + HWRMVibraCommand::TPulseVibraCmdDataPackage dataPckg(vibraData); + data->iTransId = iPluginHandler->ProcessCommandL(HWRMVibraCommand::EPulseVibraCmdId, dataPckg, this); + + // data still needed, do not destroy, just pop + CleanupStack::Pop( data ); + + // Add data to list + iTransactionList->AddTransaction( data ); + + // Control of overlapping pulses/normal vibration requests is not in hands of HWRM, + // when pulse length is configured to be handled by vibra driver. That is why + // client data may not be set to common vibra service. + + iStateSetAfterReservation = ETrue; + } + + // Store the latest status in case vibra gets suspended before next plugin call. + iLastStatus = CHWRMVibra::EVibraStatusOn; + iLastIntensity = aIntensity; + } + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::PulseVibraL - return" ) ); + + } + + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::StopVibraL +// Stops vibra. No harm calling this just in case +// even if vibra is already stopped. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::StopVibraL(const RMessage2& aMessage, + TBool aForceStop, + TBool aFinalStop) + { + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::StopVibraL(%d,%d)" ), aForceStop, aFinalStop ); + + __ASSERT_ALWAYS(iPluginHandler, User::Panic(KPanicCategory, EPanicBadHandle)); + + TBool forceStop(aForceStop); + + // Stop any ongoing timers + iVibraTimer->Cancel(); + + ReleasePulseData(); + // Reset this service's client data. + // This way any other (if any) service's interrupted vibration is restarted. + iCommonService.ResetClientData( this ); + + + + // Check from active reserver if it is ok for them that we stop vibra. + // This is necessary if active reserver is just reserving vibra but hasn't set vibra state explicitly + // after reservation. Otherwise it is possible that vibra will be left on forever. + // Note: This will sometimes result in unnecessary stop calls from suspended sessions when active session has not + // explicitly set vibra on/off, but this is the only way to ensure that the necessary stop calls go through. + CHWRMService* activeReserver = iReservationHandler->GetActiveReserver(KHWRMAllSubResources); + if ( activeReserver ) + { + if ( (static_cast(activeReserver)) == this ) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::StopVibraL - This session is active reserver, no need to force stop.") ); + } + else if ( (static_cast(activeReserver))->OkToStopVibra() ) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::StopVibraL - Active reserver has not used vibra since reservation - Force stop vibra.") ); + forceStop = ETrue; + } + else + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::StopVibraL - Active reserver has been using vibra after reservation, no need to force stop.") ); + } + } + else + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::StopVibraL - No active reserver found, no need to force stop.") ); + } + + if ( forceStop || !iSuspended ) + { + // Check reservation. + if ( !forceStop && iReservationHandler->IsReserved(this, KHWRMAllSubResources) ) + { + User::Leave(KErrInUse); + } + + // create new data (TransId is updated later) + THWRMPluginRequestData* data = new (ELeave) THWRMPluginRequestData(aMessage, 0, 0, EFalse); // commandId is not important + CleanupStack::PushL( data ); + + // No data, pass empty descriptor + TBuf8<1> emptyDes; + + // Do not require callback on final stopping of vibra + CHWRMService* callback = NULL; + if ( !aFinalStop ) + { + callback = this; + } + + data->iTransId = iPluginHandler->ProcessCommandL(HWRMVibraCommand::EStopVibraCmdId, emptyDes, callback); + + // data still needed, do not destroy, just pop + CleanupStack::Pop( data ); + + // Add data to list + iTransactionList->AddTransaction( data ); + + iStateSetAfterReservation = ETrue; + } + else + { + // complete message if suspended, as there will not be ProcessResponseL + if ( aMessage.Handle() ) + { + aMessage.Complete(KErrNone); + } + } + + // Store the latest status in case vibra gets suspended before next plugin call. + iLastStatus = CHWRMVibra::EVibraStatusStopped; + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::StopVibraL - return" ) ); + + } + + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ProcessResponseL +// Handles Vibra requests responses. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ProcessResponseL( TInt aCommandId, TUint8 aTransId, TDesC8& aData, TBool aTimeout) + { + COMPONENT_TRACE4(_L( "HWRM Server - CHWRMVibraService::ProcessResponseL(0x%x, 0x%x, , 0x%x)" ), aCommandId, aTransId, aTimeout ); + + TInt pluginErr(KErrNone); // Error came from plugin as data (or timeout). Used to complete RMessage. + TInt contextErr(KErrNone); // Error in context, i.e. bad handle or descriptor. Used to leave. + + // Unpack the package. All vibra messages contain only possible error code + // in return package. + if ( !aTimeout && aData.Size() != sizeof(TInt) ) + { + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::ProcessResponseL - Data size mismatch, expected: 0x%x, got 0x%x" ), sizeof(TInt), aData.Size() ); + contextErr = KErrBadDescriptor; + pluginErr = KErrBadDescriptor; + } + else + { + // If response was caused by timeout, set that as the error. + // Timeout handled this way instead of just returning KErrTimeout in aData because + // aData format is not known in plugin handler and in theoretically some new commands + // may also return different response than just error code in future. + if ( aTimeout ) + { + pluginErr = KErrTimedOut; + } + else + { + HWRMVibraCommand::TErrorCodeResponsePackage errPckg; + errPckg.Copy(aData); + pluginErr = errPckg(); + } + + if ( pluginErr != KErrNone ) + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::ProcessResponseL - Error: %d" ), pluginErr ); + } + + // Update vibra status PS state value + if ( !iPrivilegedClient && + ( ( (iActiveTimerId == KHWRMVibraTimerID) && (iVibraCommonData.VibraState() != CHWRMVibra::EVibraModeON ) ) || + ( (iActiveTimerId != KHWRMVibraTimerID) && (iVibraCommonData.VibraFeedbackState() != CHWRMVibra::EVibraFeedbackModeON) ) ) ) + { + // This can presumably happen if there was ongoing plugin call when + // vibra was turned off. + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusNotAllowed, iPrivilegedClient); + + // Set vibra timer for immediate shutdown if commandid was not stop + if ( aCommandId != HWRMVibraCommand::EStopVibraCmdId ) + { + iVibraTimer->Set(1); + ReleasePulseData(); + } + } + else + { + if ( pluginErr != KErrNone ) + { + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusUnknown, iPrivilegedClient); + } + else + { + switch ( aCommandId ) + { + case HWRMVibraCommand::EStartVibraCmdId: + { + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusOn, iPrivilegedClient); + break; + } + case HWRMVibraCommand::EStartVibraWithDefaultSettingsCmdId: + { + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusOn, iPrivilegedClient); + break; + } + case HWRMVibraCommand::EPulseVibraCmdId: + { + // It may cause quite a lot of overhead to publish vibra status for short pulses. + // iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusOn, iPrivilegedClient); + break; + } + + case HWRMVibraCommand::EStopVibraCmdId: + { + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusStopped, iPrivilegedClient); + break; + } + default: + { + iVibraCommonData.PublishVibraStatus(CHWRMVibra::EVibraStatusUnknown, iPrivilegedClient); + break; + } + } + } + } + } + + // Complete request and remove delete transaction + contextErr = CompleteRequest(aTransId, pluginErr); + + // Leave if there is error in context + User::LeaveIfError(contextErr); + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ProcessResponseL - return" ) ); + } + + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::GenericTimerFired +// Handles vibra cutoff timer firing. Adjust vibra intensity and stops vibra. +// There is only one regular vibra timer active at a time. It is used for vibra start calls. +// If vibra pulse is requested, new timer is setup. If pulse timer expires and vibra or any other +// pulse timer is still active, vibration intensity must be adjusted accordingly. If all pulse +// timers and vibra timer have expired, stop vibra. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::GenericTimerFired(TInt aTimerId, TBool aCutOff) + { + COMPONENT_TRACE5( _L( "HWRM Server - CHWRMVibraService::GenericTimerFired, iLastIntensity %d, iActiveTimerId %d, aTimerId %d, aCutOff %d" ), + iLastIntensity, iActiveTimerId, aTimerId, aCutOff ); + + // if cutoff because maximum ontime set the lock period + if ( aCutOff ) + { + iVibraCommonData.LockVibra(); + } + + RMessage2 dummy; + TInt err(KErrNone); + TInt count( iPulseData.Count() ); + TBool changeIntensity( EFalse ); + TBool pulseTimersActive( EFalse ); + TBool succeedingFound( EFalse ); + + if( aTimerId < count ) + { + // Update last intensity from expired pulse timer to ACTIVE timer succeeding it, + // because otherwise it has old information about intensity, which must + // be set when it expires. This works, because timer objects only need to + // remember last intensity. If timer expires, but it is not "active" one, then + // intensity is not changed and intensity if just passed to next one in queue. + for( TInt i = aTimerId+1; i < count; i++ ) + { + if( iPulseData[i]->Timer().IsActive() ) + { + COMPONENT_TRACE5(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - upgrading last intensity from %d (%d) to %d (%d) "), + aTimerId, iPulseData[aTimerId]->LastIntensity(), i, iPulseData[i]->LastIntensity() ); + COMPONENT_TRACE5(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - upgrading timer id from %d (%d) to %d (%d) " ), + aTimerId, iPulseData[aTimerId]->LastTimerId(), i, iPulseData[i]->LastTimerId() ); + iPulseData[i]->SetLastIntensity( iPulseData[aTimerId]->LastIntensity() ); + iPulseData[i]->SetLastTimerId( iPulseData[aTimerId]->LastTimerId() ); + succeedingFound = ETrue; + break; + } + } + } + + // Check if any pulse timers active + for( TInt i = 0; i < count; i++ ) + { + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - pulse timer %d status: %d" ), i, iPulseData[i]->Timer().IsActive() ); + if( iPulseData[i]->Timer().IsActive() ) + { + pulseTimersActive = ETrue; + } + } + + COMPONENT_TRACE2( _L( "HWRM Server - CHWRMVibraService::GenericTimerFired - vibra timer status: %d" ), iVibraTimer->IsActive() ); + + // If timer expired is not last active timer, we must not change intensity, + // because intensity has been changed when new timer setup and intensity + // gets updated only if it expires or new pulse request arrives. + if( aTimerId == iActiveTimerId ) + { + changeIntensity = ETrue; + + if( (aTimerId == KHWRMVibraTimerID || !succeedingFound) && pulseTimersActive ) + { + // If active timer expired was vibra timer or succeeding (=active) pulse timer was not found + // and there are still active pulse timers, update timer id and intensity accordingly. + // First pulse timer from end is new active. + for( TInt i = count-1; i >= 0; i-- ) + { + if( iPulseData[i]->Timer().IsActive() ) + { + iActiveTimerId = i; + iLastIntensity = iPulseData[i]->Intensity(); + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - upgraded active timer id to %d and intensity to %d" ), + iActiveTimerId, iLastIntensity ); + break; + } + } + } + else if( aTimerId != KHWRMVibraTimerID && iVibraTimer->IsActive() && !pulseTimersActive ) + { + // If active timer expired was not vibra timer and it still active and no more pulse + // timers, update timer id and intensity accordingly + iActiveTimerId = KHWRMVibraTimerID; + if( aTimerId < count ) + { + iLastIntensity = iPulseData[aTimerId]->LastIntensity(); + } + COMPONENT_TRACE3(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - upgraded active timer id to %d and intensity to %d" ), + iActiveTimerId, iLastIntensity ); + } + else + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - active timer id and intensity not updated" ) ); + } + } + + if( !pulseTimersActive ) + { + // Remove expired pulse timers + ReleasePulseData(); + } + + // If cutoff or there are no active timers left, stop vibra + if( aCutOff || (!pulseTimersActive && !iVibraTimer->IsActive()) ) + { + TRAP(err, StopVibraL(dummy)); + + if ( err != KErrNone ) + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - Error Stopping vibra: %d" ), err ); + } + } + else if( changeIntensity ) + { + TRAP(err, ChangeVibraIntensityL()); + + if ( err != KErrNone ) + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - Error changing intensity: %d" ), err ); + } + } + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::GenericTimerFired - return" ) ); + + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ChangeVibraIntensityL +// Changes the device vibration intensity to previous active intensity. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ChangeVibraIntensityL() + { + COMPONENT_TRACE2(_L( "HWRM Server - CHWRMVibraService::ChangeVibraIntensityL() - new intensity %d" ), iLastIntensity ); + + // Ignore Coverity false positive as uninitialized variable. + // Since no response is sent back to the client, only a empty message is created here. + // Message handle of this will be initialized to NULL in the default constructor. + // coverity[var_decl] + RMessage2 dummy; + + // Create new data (TransId is updated later, commandId is not important) + THWRMPluginRequestData* data = new (ELeave) THWRMPluginRequestData(dummy, 0, 0, EFalse); + CleanupStack::PushL( data ); + + if ( iLastIntensity == KUseDefaultIntensity ) + { + // No data, pass empty descriptor + TBuf8<1> emptyDes; + data->iTransId = iPluginHandler->ProcessCommandL(HWRMVibraCommand::EStartVibraWithDefaultSettingsCmdId, emptyDes, this); + } + else + { + HWRMVibraCommand::TStartVibraCmdDataPackage dataPckg(iLastIntensity); + data->iTransId = iPluginHandler->ProcessCommandL(HWRMVibraCommand::EStartVibraCmdId, dataPckg, this); + } + + // data still needed, do not destroy, just pop + CleanupStack::Pop( data ); + + // Add data to list + iTransactionList->AddTransaction( data ); + } + + + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::SuspendSubResource +// Suspends vibra. Since vibra has no subresources, whole vibra is affected. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::SuspendSubResource(TInt /*aSubResource*/) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::SuspendSubResource()" ) ); + + if ( iLastStatus == CHWRMVibra::EVibraStatusOn ) + { + // Resume base state, i.e. stop vibra + RMessage2 dummy; + TRAP_IGNORE(StopVibraL(dummy)); + + // Restore iLastStatus + iLastStatus = CHWRMVibra::EVibraStatusOn; + } + + iSuspended = ETrue; + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::SuspendSubResource - return" ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ResumeSubResource +// Resumes vibra. Since vibra has no subresources, whole vibra is affected. +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ResumeSubResource(TInt /*aSubResource*/) + { + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ResumeSubResource()" ) ); + + iSuspended = EFalse; + + RMessage2 dummy; + + // Restore last state + TInt err(KErrNone); + if ( iLastStatus == CHWRMVibra::EVibraStatusOn ) + { + TRAP(err, StartVibraL(0, iLastIntensity, dummy, EFalse)); + } + else + { + TRAP(err, StopVibraL(dummy)); + } + + COMPONENT_TRACE1(_L( "HWRM Server - CHWRMVibraService::ResumeSubResource - return" ) ); + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::ActivateSubResource +// Vibra doesn't support activation/deactivation based on device state +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::ActivateSubResource(TInt /*aSubResource*/, TBool /*aActivate*/) + { + // Do nothing + } + +// ----------------------------------------------------------------------------- +// CHWRMVibraService::OkToStopVibra +// Checks if it is ok to stop vibra from another session. +// ----------------------------------------------------------------------------- +// +TBool CHWRMVibraService::OkToStopVibra() + { + return !iStateSetAfterReservation; + } + + +// ----------------------------------------------------------------------------- +// CPulseData::CPulseData +// ----------------------------------------------------------------------------- +// + + +CHWRMVibraService::CPulseData::CPulseData( CHWRMGenericTimer& aVibraTimer, + const TInt aLastIntensity, + const TInt aIntensity, + const TInt aLastTimerId ) + :iVibraTimer(aVibraTimer), + iLastIntensity(aLastIntensity), + iIntensity(aIntensity), + iLastTimerId(aLastTimerId) + { + COMPONENT_TRACE1(_L( "HWRM Server - CPulseData::CPulseData()" ) ); + } + + + +// ----------------------------------------------------------------------------- +// CPulseData::NewL +// ----------------------------------------------------------------------------- +// +CHWRMVibraService::CPulseData* +CHWRMVibraService::CPulseData::NewL( CHWRMGenericTimer& aVibraTimer, + const TInt aLastIntensity, + const TInt aIntensity, + const TInt aLastTimerId ) + { + COMPONENT_TRACE4(_L( "HWRM Server - CPulseData::NewL(0x%x, %d, %d)" ), &aVibraTimer, aLastIntensity, aIntensity); + + CPulseData* self = new( ELeave ) + CPulseData(aVibraTimer, aLastIntensity, aIntensity, aLastTimerId); + + COMPONENT_TRACE2(_L( "HWRM Server - CPulseData::NewL - return 0x%x" ), self); + + return self; + } + +// ----------------------------------------------------------------------------- +// CPulseData::~CPulseData +// ----------------------------------------------------------------------------- +// +CHWRMVibraService::CPulseData::~CPulseData() + { + COMPONENT_TRACE1(_L("HWRM Server - CPulseData::~CPulseData()")); + + iVibraTimer.Cancel(); + } + +// ----------------------------------------------------------------------------- +// CPulseData::Timer +// ----------------------------------------------------------------------------- +// +CHWRMGenericTimer& CHWRMVibraService::CPulseData::Timer() const + { + return iVibraTimer; + } + + +// ----------------------------------------------------------------------------- +// CPulseData::LastIntensity +// ----------------------------------------------------------------------------- +// +TInt CHWRMVibraService::CPulseData::LastIntensity() const + { + return iLastIntensity; + } + +// ----------------------------------------------------------------------------- +// CPulseData::Intensity +// ----------------------------------------------------------------------------- +// +TInt CHWRMVibraService::CPulseData::Intensity() const + { + return iIntensity; + } + +// ----------------------------------------------------------------------------- +// CPulseData::SetLastIntensity +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::CPulseData::SetLastIntensity(TInt aIntensity) + { + iLastIntensity = aIntensity; + } + +// ----------------------------------------------------------------------------- +// CPulseData::LastTimerId +// ----------------------------------------------------------------------------- +// +TInt CHWRMVibraService::CPulseData::LastTimerId() const + { + return iLastTimerId; + } + +// ----------------------------------------------------------------------------- +// CPulseData::SetLastTimerId +// ----------------------------------------------------------------------------- +// +void CHWRMVibraService::CPulseData::SetLastTimerId(TInt aTimerId) + { + iLastTimerId = aTimerId; + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// End of File