/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Adjust the controller's power states. */ #include "OverrideLog.h" #include "PowerSwitch.h" #include "NfcJniUtil.h" #include "config.h" #include "SecureElement.h" namespace android { void doStartupConfig (); } extern bool gActivated; extern SyncEvent gDeactivatedEvent; PowerSwitch PowerSwitch::sPowerSwitch; const PowerSwitch::PowerActivity PowerSwitch::DISCOVERY=0x01; const PowerSwitch::PowerActivity PowerSwitch::SE_ROUTING=0x02; const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED=0x04; const PowerSwitch::PowerActivity PowerSwitch::HOST_ROUTING=0x08; /******************************************************************************* ** ** Function: PowerSwitch ** ** Description: Initialize member variables. ** ** Returns: None ** *******************************************************************************/ PowerSwitch::PowerSwitch () : mCurrLevel (UNKNOWN_LEVEL), mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN), mExpectedDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN), mDesiredScreenOffPowerState (0), mCurrActivity(0) { } /******************************************************************************* ** ** Function: ~PowerSwitch ** ** Description: Release all resources. ** ** Returns: None ** *******************************************************************************/ PowerSwitch::~PowerSwitch () { } /******************************************************************************* ** ** Function: getInstance ** ** Description: Get the singleton of this object. ** ** Returns: Reference to this object. ** *******************************************************************************/ PowerSwitch& PowerSwitch::getInstance () { return sPowerSwitch; } /******************************************************************************* ** ** Function: initialize ** ** Description: Initialize member variables. ** ** Returns: None ** *******************************************************************************/ void PowerSwitch::initialize (PowerLevel level) { static const char fn [] = "PowerSwitch::initialize"; unsigned long num = 0; mMutex.lock (); ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level); if (GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &num, sizeof(num))) mDesiredScreenOffPowerState = (int) num; ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState); switch (level) { case FULL_POWER: mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL; mCurrLevel = level; break; case UNKNOWN_LEVEL: mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; mCurrLevel = level; break; default: ALOGE ("%s: not handled", fn); break; } mMutex.unlock (); } /******************************************************************************* ** ** Function: getLevel ** ** Description: Get the current power level of the controller. ** ** Returns: Power level. ** *******************************************************************************/ PowerSwitch::PowerLevel PowerSwitch::getLevel () { PowerLevel level = UNKNOWN_LEVEL; mMutex.lock (); level = mCurrLevel; mMutex.unlock (); return level; } /******************************************************************************* ** ** Function: setLevel ** ** Description: Set the controller's power level. ** level: power level. ** ** Returns: True if ok. ** *******************************************************************************/ bool PowerSwitch::setLevel (PowerLevel newLevel) { static const char fn [] = "PowerSwitch::setLevel"; bool retval = false; mMutex.lock (); ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel); if (mCurrLevel == newLevel) { retval = true; goto TheEnd; } if (mCurrLevel == UNKNOWN_LEVEL) { ALOGE ("%s: unknown power level", fn); goto TheEnd; } if ( (mCurrLevel == LOW_POWER && newLevel == FULL_POWER) || (mCurrLevel == FULL_POWER && newLevel == LOW_POWER) ) { mMutex.unlock (); SyncEventGuard g (gDeactivatedEvent); if (gActivated) { ALOGD("%s: wait for deactivation", fn); gDeactivatedEvent.wait (); } mMutex.lock (); } switch (newLevel) { case FULL_POWER: if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP) retval = setPowerOffSleepState (false); break; case LOW_POWER: case POWER_OFF: if (isPowerOffSleepFeatureEnabled()) retval = setPowerOffSleepState (true); else if (mDesiredScreenOffPowerState == 1) //.conf file desires full-power { mCurrLevel = FULL_POWER; retval = true; } break; default: ALOGE ("%s: not handled", fn); break; } TheEnd: mMutex.unlock (); return retval; } /******************************************************************************* ** ** Function: setModeOff ** ** Description: Set a mode to be deactive. ** ** Returns: True if any mode is still active. ** *******************************************************************************/ bool PowerSwitch::setModeOff (PowerActivity deactivated) { bool retVal = false; mMutex.lock (); mCurrActivity &= ~deactivated; retVal = mCurrActivity != 0; ALOGD ("PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x", deactivated, mCurrActivity); mMutex.unlock (); return retVal; } /******************************************************************************* ** ** Function: setModeOn ** ** Description: Set a mode to be active. ** ** Returns: True if any mode is active. ** *******************************************************************************/ bool PowerSwitch::setModeOn (PowerActivity activated) { bool retVal = false; mMutex.lock (); mCurrActivity |= activated; retVal = mCurrActivity != 0; ALOGD ("PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated, mCurrActivity); mMutex.unlock (); return retVal; } /******************************************************************************* ** ** Function: setPowerOffSleepState ** ** Description: Adjust controller's power-off-sleep state. ** sleep: whether to enter sleep state. ** ** Returns: True if ok. ** *******************************************************************************/ bool PowerSwitch::setPowerOffSleepState (bool sleep) { static const char fn [] = "PowerSwitch::setPowerOffSleepState"; ALOGD ("%s: enter; sleep=%u", fn, sleep); tNFA_STATUS stat = NFA_STATUS_FAILED; bool retval = false; if (sleep) //enter power-off-sleep state { //make sure the current power state is ON if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP) { SyncEventGuard guard (mPowerStateEvent); mExpectedDeviceMgtPowerState = NFA_DM_PWR_MODE_OFF_SLEEP; //if power adjustment is ok, then this is the expected state ALOGD ("%s: try power off", fn); stat = NFA_PowerOffSleepMode (TRUE); if (stat == NFA_STATUS_OK) { mPowerStateEvent.wait (); mCurrLevel = LOW_POWER; } else { ALOGE ("%s: API fail; stat=0x%X", fn, stat); goto TheEnd; } } else { ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn, deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } } else //exit power-off-sleep state { //make sure the current power state is OFF if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) { SyncEventGuard guard (mPowerStateEvent); mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; mExpectedDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL; //if power adjustment is ok, then this is the expected state ALOGD ("%s: try full power", fn); stat = NFA_PowerOffSleepMode (FALSE); if (stat == NFA_STATUS_OK) { mPowerStateEvent.wait (); if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) { ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn, deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } android::doStartupConfig (); mCurrLevel = FULL_POWER; } else { ALOGE ("%s: API fail; stat=0x%X", fn, stat); goto TheEnd; } } else { ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn, deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } } retval = true; TheEnd: ALOGD ("%s: exit; return %u", fn, retval); return retval; } /******************************************************************************* ** ** Function: deviceMgtPowerStateToString ** ** Description: Decode power level to a string. ** deviceMgtPowerState: power level. ** ** Returns: Text representation of power level. ** *******************************************************************************/ const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState) { switch (deviceMgtPowerState) { case NFA_DM_PWR_MODE_FULL: return "DM-FULL"; case NFA_DM_PWR_MODE_OFF_SLEEP: return "DM-OFF"; default: return "DM-unknown????"; } } /******************************************************************************* ** ** Function: powerLevelToString ** ** Description: Decode power level to a string. ** level: power level. ** ** Returns: Text representation of power level. ** *******************************************************************************/ const char* PowerSwitch::powerLevelToString (PowerLevel level) { switch (level) { case UNKNOWN_LEVEL: return "PS-UNKNOWN"; case FULL_POWER: return "PS-FULL"; case LOW_POWER: return "PS-LOW-POWER"; case POWER_OFF: return "PS-POWER-OFF"; default: return "PS-unknown????"; } } /******************************************************************************* ** ** Function: abort ** ** Description: Abort and unblock currrent operation. ** ** Returns: None ** *******************************************************************************/ void PowerSwitch::abort () { static const char fn [] = "PowerSwitch::abort"; ALOGD ("%s", fn); SyncEventGuard guard (mPowerStateEvent); mPowerStateEvent.notifyOne (); } /******************************************************************************* ** ** Function: deviceManagementCallback ** ** Description: Callback function for the stack. ** event: event ID. ** eventData: event's data. ** ** Returns: None ** *******************************************************************************/ void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData) { static const char fn [] = "PowerSwitch::deviceManagementCallback"; switch (event) { case NFA_DM_PWR_MODE_CHANGE_EVT: { tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode; ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=0x%X; device mgt power state=%s (0x%X)", fn, power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode), power_mode.power_mode); SyncEventGuard guard (sPowerSwitch.mPowerStateEvent); if (power_mode.status == NFA_STATUS_OK) { //the event data does not contain the newly configured power mode, //so this code assigns the expected value sPowerSwitch.mCurrDeviceMgtPowerState = sPowerSwitch.mExpectedDeviceMgtPowerState; } sPowerSwitch.mPowerStateEvent.notifyOne (); } break; } } /******************************************************************************* ** ** Function: isPowerOffSleepFeatureEnabled ** ** Description: Whether power-off-sleep feature is enabled in .conf file. ** ** Returns: True if feature is enabled. ** *******************************************************************************/ bool PowerSwitch::isPowerOffSleepFeatureEnabled () { return mDesiredScreenOffPowerState == 0; }