You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
484 lines
15 KiB
484 lines
15 KiB
/*
|
|
* 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;
|
|
}
|