| /* |
| * 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. |
| */ |
| /****************************************************************************** |
| * |
| * The original Work has been changed by NXP Semiconductors. |
| * |
| * Copyright (C) 2015 NXP Semiconductors |
| * |
| * 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 "SecureElement.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; |
| } |