/* * 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 "PowerSwitch.h" #include "NfcJniUtil.h" #include "nfc_config.h" #include <android-base/stringprintf.h> #include <base/logging.h> using android::base::StringPrintf; namespace android { void doStartupConfig(); } extern bool gActivated; extern bool nfc_debug_enabled; 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"; mMutex.lock(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: level=%s (%u)", fn, powerLevelToString(level), level); if (NfcConfig::hasKey(NAME_SCREEN_OFF_POWER_STATE)) mDesiredScreenOffPowerState = (int)NfcConfig::getUnsigned(NAME_SCREEN_OFF_POWER_STATE); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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: LOG(ERROR) << StringPrintf("%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(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel); if (mCurrLevel == newLevel) { retval = true; goto TheEnd; } if (mCurrLevel == UNKNOWN_LEVEL) { LOG(ERROR) << StringPrintf("%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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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: LOG(ERROR) << StringPrintf("%s: not handled", fn); break; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: actual power level=%s", fn, powerLevelToString(mCurrLevel)); TheEnd: mMutex.unlock(); return retval; } bool PowerSwitch::setScreenOffPowerState(ScreenOffPowerState newState) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("PowerSwitch::setScreenOffPowerState: level=%s (%u)", screenOffPowerStateToString(newState), newState); mMutex.lock(); mDesiredScreenOffPowerState = (int)newState; mMutex.unlock(); return true; } /******************************************************************************* ** ** 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: try power off", fn); stat = NFA_PowerOffSleepMode(TRUE); if (stat == NFA_STATUS_OK) { mPowerStateEvent.wait(); mCurrLevel = LOW_POWER; } else { LOG(ERROR) << StringPrintf("%s: API fail; stat=0x%X", fn, stat); goto TheEnd; } } else { LOG(ERROR) << StringPrintf( "%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 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: try full power", fn); stat = NFA_PowerOffSleepMode(FALSE); if (stat == NFA_STATUS_OK) { mPowerStateEvent.wait(); if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) { LOG(ERROR) << StringPrintf( "%s: unable to full power; curr device mgt power stat=%s (%u)", fn, deviceMgtPowerStateToString(mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } android::doStartupConfig(); mCurrLevel = FULL_POWER; } else { LOG(ERROR) << StringPrintf("%s: API fail; stat=0x%X", fn, stat); goto TheEnd; } } else { LOG(ERROR) << StringPrintf( "%s: not in power-off state; curr device mgt power state=%s (%u)", fn, deviceMgtPowerStateToString(mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } } retval = true; TheEnd: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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_t 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: screenOffPowerStateToString ** ** Description: Decode power level to a string. ** level: power level. ** ** Returns: Text representation of power level. ** *******************************************************************************/ const char* PowerSwitch::screenOffPowerStateToString( ScreenOffPowerState state) { switch (state) { case POWER_STATE_OFF: return "SOPS-POWER_OFF"; case POWER_STATE_FULL: return "SOPS-FULL"; case POWER_STATE_CARD_EMULATION: return "SOPS-CARD_EMULATION"; default: return "SOPS-unknown????"; } } /******************************************************************************* ** ** Function: abort ** ** Description: Abort and unblock currrent operation. ** ** Returns: None ** *******************************************************************************/ void PowerSwitch::abort() { static const char fn[] = "PowerSwitch::abort"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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_t 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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; }