summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rtl8192ce/core/rtw_pwrctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rtl8192ce/core/rtw_pwrctrl.c')
-rwxr-xr-xdrivers/net/wireless/rtl8192ce/core/rtw_pwrctrl.c1404
1 files changed, 1404 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtl8192ce/core/rtw_pwrctrl.c b/drivers/net/wireless/rtl8192ce/core/rtw_pwrctrl.c
new file mode 100755
index 000000000000..1301b204af05
--- /dev/null
+++ b/drivers/net/wireless/rtl8192ce/core/rtw_pwrctrl.c
@@ -0,0 +1,1404 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_PWRCTRL_C_
+
+#include <drv_conf.h>
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+
+
+#ifdef CONFIG_IPS
+void ips_enter(_adapter * padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_INTEL_PROXIM
+ if(padapter->proximity.proxim_on==_TRUE){
+ return;
+ }
+#endif
+ _enter_pwrlock(&pwrpriv->lock);
+
+ pwrpriv->bips_processing = _TRUE;
+
+ // syn ips_mode with request
+ pwrpriv->ips_mode = pwrpriv->ips_mode_req;
+
+ pwrpriv->ips_enter_cnts++;
+ DBG_871X("==>ips_enter cnts:%d\n",pwrpriv->ips_enter_cnts);
+
+ if(rf_off == pwrpriv->change_rfpwrstate )
+ {
+ DBG_871X("==>power_saving_ctrl_wk_hdl change rf to OFF...LED(0x%08x).... \n\n",rtw_read32(padapter,0x4c));
+
+ if(pwrpriv->ips_mode == IPS_LEVEL_2)
+ pwrpriv->bkeepfwalive = _TRUE;
+
+ rtw_ips_pwr_down(padapter);
+ pwrpriv->rf_pwrstate = rf_off;
+ }
+ pwrpriv->bips_processing = _FALSE;
+ _exit_pwrlock(&pwrpriv->lock);
+
+}
+
+int ips_leave(_adapter * padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct security_priv* psecuritypriv=&(padapter->securitypriv);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int result = _SUCCESS;
+ sint keyid;
+ _enter_pwrlock(&pwrpriv->lock);
+ if((pwrpriv->rf_pwrstate == rf_off) &&(!pwrpriv->bips_processing))
+ {
+ pwrpriv->change_rfpwrstate = rf_on;
+ pwrpriv->ips_leave_cnts++;
+ DBG_871X("==>ips_leave cnts:%d\n",pwrpriv->ips_leave_cnts);
+
+ result = rtw_ips_pwr_up(padapter);
+ pwrpriv->bips_processing = _TRUE;
+ pwrpriv->rf_pwrstate = rf_on;
+
+ if((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm))
+ {
+ DBG_871X("==>%s,channel(%d),processing(%x)\n",__FUNCTION__,padapter->mlmeextpriv.cur_channel,pwrpriv->bips_processing);
+ set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ for(keyid=0;keyid<4;keyid++){
+ if(pmlmepriv->key_mask & BIT(keyid)){
+ if(keyid == psecuritypriv->dot11PrivacyKeyIndex)
+ result=rtw_set_key(padapter,psecuritypriv, keyid, 1);
+ else
+ result=rtw_set_key(padapter,psecuritypriv, keyid, 0);
+ }
+ }
+ }
+
+ DBG_871X("==> ips_leave.....LED(0x%08x)...\n",rtw_read32(padapter,0x4c));
+ pwrpriv->bips_processing = _FALSE;
+
+ pwrpriv->bkeepfwalive = _FALSE;
+
+
+ }
+ _exit_pwrlock(&pwrpriv->lock);
+ return result;
+}
+
+
+#endif
+
+#ifdef CONFIG_AUTOSUSPEND
+extern void autosuspend_enter(_adapter* padapter);
+extern int autoresume_enter(_adapter* padapter);
+#endif
+
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+int rtw_hw_suspend(_adapter *padapter );
+int rtw_hw_resume(_adapter *padapter);
+#endif
+
+#if defined (PLATFORM_LINUX)||defined (PLATFORM_FREEBSD)
+void rtw_ps_processor(_adapter*padapter)
+{
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &( padapter->wdinfo );
+#endif //CONFIG_P2P
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ rt_rf_power_state rfpwrstate;
+#endif //SUPPORT_HW_RFOFF_DETECTED
+
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ if(pwrpriv->bips_processing == _TRUE) return;
+
+ //DBG_871X("==> fw report state(0x%x)\n",rtw_read8(padapter,0x1ca));
+ if(padapter->pwrctrlpriv.bHWPwrPindetect)
+ {
+ #ifdef CONFIG_AUTOSUSPEND
+ if(padapter->registrypriv.usbss_enable)
+ {
+ if(pwrpriv->rf_pwrstate == rf_on)
+ {
+ if(padapter->net_closed == _TRUE)
+ pwrpriv->ps_flag = _TRUE;
+
+ rfpwrstate = RfOnOffDetect(padapter);
+ DBG_871X("@@@@- #1 %s==> rfstate:%s \n",__FUNCTION__,(rfpwrstate==rf_on)?"rf_on":"rf_off");
+ if(rfpwrstate!= pwrpriv->rf_pwrstate)
+ {
+ if(rfpwrstate == rf_off)
+ {
+ pwrpriv->change_rfpwrstate = rf_off;
+
+ pwrpriv->bkeepfwalive = _TRUE;
+ pwrpriv->brfoffbyhw = _TRUE;
+
+ autosuspend_enter(padapter);
+ }
+ }
+ }
+ }
+ else
+ #endif //CONFIG_AUTOSUSPEND
+ {
+ rfpwrstate = RfOnOffDetect(padapter);
+ DBG_871X("@@@@- #2 %s==> rfstate:%s \n",__FUNCTION__,(rfpwrstate==rf_on)?"rf_on":"rf_off");
+
+ if(rfpwrstate!= pwrpriv->rf_pwrstate)
+ {
+ if(rfpwrstate == rf_off)
+ {
+ pwrpriv->change_rfpwrstate = rf_off;
+ pwrpriv->brfoffbyhw = _TRUE;
+ padapter->bCardDisableWOHSM = _TRUE;
+ rtw_hw_suspend(padapter );
+ }
+ else
+ {
+ pwrpriv->change_rfpwrstate = rf_on;
+ rtw_hw_resume(padapter );
+ }
+ DBG_871X("current rf_pwrstate(%s)\n",(pwrpriv->rf_pwrstate == rf_off)?"rf_off":"rf_on");
+ }
+ }
+ pwrpriv->pwr_state_check_cnts ++;
+ }
+#endif //SUPPORT_HW_RFOFF_DETECTED
+
+ #if defined(CONFIG_CONCURRENT_MODE)
+ return; /* Skip power saving for concurrent mode */
+ #endif
+
+ if( pwrpriv->ips_mode_req == IPS_NONE) return;
+
+ if((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4)==0))
+ {
+ if ( (check_fwstate(pmlmepriv, _FW_LINKED|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ||
+ (padapter->bup == _FALSE)
+ #ifdef CONFIG_P2P
+ || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
+ #endif //CONFIG_P2P
+ )
+ {
+ return;
+ }
+
+ DBG_871X("==>%s .fw_state(%x)\n",__FUNCTION__,get_fwstate(pmlmepriv));
+ pwrpriv->change_rfpwrstate = rf_off;
+
+ #ifdef CONFIG_AUTOSUSPEND
+ if(padapter->registrypriv.usbss_enable)
+ {
+ if(padapter->pwrctrlpriv.bHWPwrPindetect)
+ pwrpriv->bkeepfwalive = _TRUE;
+
+ if(padapter->net_closed == _TRUE)
+ pwrpriv->ps_flag = _TRUE;
+
+ padapter->bCardDisableWOHSM = _TRUE;
+ autosuspend_enter(padapter);
+ }
+ else if(padapter->pwrctrlpriv.bHWPwrPindetect)
+ {
+ }
+ else
+ #endif //CONFIG_AUTOSUSPEND
+ {
+ #ifdef CONFIG_IPS
+ ips_enter(padapter);
+ #endif
+ }
+ }
+
+
+}
+
+void pwr_state_check_handler(void *FunctionContext);
+void pwr_state_check_handler(void *FunctionContext)
+{
+ _adapter *padapter = (_adapter *)FunctionContext;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &( padapter->wdinfo );
+#endif //CONFIG_P2P
+ //DBG_871X("%s\n", __FUNCTION__);
+
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ //DBG_871X("%s...bHWPwrPindetect(%d)\n",__FUNCTION__,padapter->pwrctrlpriv.bHWPwrPindetect);
+ if(padapter->pwrctrlpriv.bHWPwrPindetect)
+ {
+ rtw_ps_cmd(padapter);
+ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+ }
+ else
+#endif
+ {
+ //if(padapter->net_closed == _TRUE) return;
+ //DBG_871X("==>%s .fw_state(%x)\n", __FUNCTION__, get_fwstate(pmlmepriv));
+ if ( (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, _FW_LINKED|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ||
+ (padapter->bup == _FALSE)
+ #ifdef CONFIG_P2P
+ || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
+ #endif //CONFIG_P2P
+ )
+ {
+ //other pwr ctrl....
+ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+ }
+ else
+ {
+ if((pwrpriv->rf_pwrstate == rf_on) &&(_FALSE == pwrpriv->bips_processing))
+ {
+ pwrpriv->change_rfpwrstate = rf_off;
+ pwrctrlpriv->pwr_state_check_cnts = 0;
+ DBG_871X("==>pwr_state_check_handler .fw_state(%x)\n",get_fwstate(pmlmepriv));
+ rtw_ps_cmd(padapter);
+ }
+
+ }
+ }
+
+
+
+}
+#endif
+
+
+#ifdef CONFIG_LPS
+/*
+ *
+ * Parameters
+ * padapter
+ * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
+ *
+ */
+void rtw_set_rpwm(PADAPTER padapter, u8 pslv)
+{
+ u8 rpwm;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+ pslv = PS_STATE(pslv);
+
+ if (pwrpriv->rpwm == pslv) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_,_drv_err_,
+ ("%s: Already set rpwm[0x%02x]!\n", __FUNCTION__, pslv));
+ return;
+ }
+
+ if ((padapter->bDriverStopped == _TRUE) ||
+ (padapter->bSurpriseRemoved == _TRUE)) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
+ __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
+ return;
+ }
+
+ rpwm = pslv | pwrpriv->tog;
+#ifdef CONFIG_LPS_LCLK
+ if ((pwrpriv->cpwm < PS_STATE_S2) && (pslv >= PS_STATE_S2))
+ rpwm |= PS_ACK;
+#endif
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm));
+
+ pwrpriv->rpwm = pslv;
+
+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
+
+ pwrpriv->tog += 0x80;
+
+ if (!(rpwm & PS_ACK)) pwrpriv->cpwm = pslv;
+
+_func_exit_;
+}
+
+u8 PS_RDY_CHECK(_adapter * padapter);
+u8 PS_RDY_CHECK(_adapter * padapter)
+{
+ u32 curr_time, delta_time;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ curr_time = rtw_get_current_time();
+
+ delta_time = curr_time -pwrpriv->DelayLPSLastTimeStamp;
+
+ if(delta_time < LPS_DELAY_TIME)
+ {
+ return _FALSE;
+ }
+
+ if ( (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) ||
+ (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) )
+ return _FALSE;
+
+ if(_TRUE == pwrpriv->bInSuspend )
+ return _FALSE;
+
+ if( (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == _FALSE) )
+ {
+ DBG_871X("Group handshake still in progress !!!\n");
+ return _FALSE;
+ }
+
+ return _TRUE;
+}
+
+void rtw_set_ps_mode(PADAPTER padapter, u8 ps_mode, u8 smart_ps)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &( padapter->wdinfo );
+#endif //CONFIG_P2P
+#ifdef CONFIG_TDLS
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ _irqL irqL;
+ int i, j;
+ _list *plist, *phead;
+ struct sta_info *ptdls_sta;
+#endif //CONFIG_TDLS
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("%s: PowerMode=%d Smart_PS=%d\n",
+ __FUNCTION__, ps_mode, smart_ps));
+
+ if(ps_mode > PM_Card_Disable) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_,_drv_err_,("ps_mode:%d error\n", ps_mode));
+ return;
+ }
+
+ if((pwrpriv->pwr_mode == ps_mode) &&
+ (pwrpriv->smart_ps == smart_ps)){
+ return;
+ }
+
+ //if(pwrpriv->pwr_mode == PS_MODE_ACTIVE)
+ if(ps_mode == PS_MODE_ACTIVE)
+ {
+#ifdef CONFIG_P2P_PS
+ if(pwdinfo->opp_ps == 0)
+#endif // CONFIG_P2P_PS
+ {
+#ifdef CONFIG_LPS_LCLK
+ _enter_pwrlock(&pwrpriv->lock);
+#endif
+ DBG_871X("rtw_set_ps_mode(): Busy Traffic , Leave 802.11 power save..\n");
+
+#ifdef CONFIG_TDLS
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ for(i=0; i< NUM_STA; i++)
+ {
+ phead = &(pstapriv->sta_hash[i]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+ {
+ ptdls_sta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ if( ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE )
+ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 0);
+ plist = get_next(plist);
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+#endif //CONFIG_TDLS
+
+ pwrpriv->smart_ps = smart_ps;
+ pwrpriv->pwr_mode = ps_mode;
+
+ rtw_set_rpwm(padapter, PS_STATE_S4);
+#ifdef CONFIG_LPS_LCLK
+{
+ u32 n = 0;
+ while (pwrpriv->cpwm != PS_STATE_S4) {
+ n++;
+ if (n == 10000) break;
+ if (padapter->bSurpriseRemoved == _TRUE) break;
+ rtw_msleep_os(1);
+ }
+ if (n == 10000)
+ printk(KERN_ERR "%s: wait CPWM to S4 too long! cpwm=0x%02x\n", __func__, pwrpriv->cpwm);
+}
+#endif
+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+ pwrpriv->bFwCurrentInPSMode = _FALSE;
+#ifdef CONFIG_LPS_LCLK
+ _exit_pwrlock(&pwrpriv->lock);
+#endif
+ }
+ }
+ else
+ {
+ if(PS_RDY_CHECK(padapter))
+ {
+#ifdef CONFIG_LPS_LCLK
+ _enter_pwrlock(&pwrpriv->lock);
+#endif
+ DBG_871X("rtw_set_ps_mode(): Enter 802.11 power save mode...\n");
+
+#ifdef CONFIG_TDLS
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ for(i=0; i< NUM_STA; i++)
+ {
+ phead = &(pstapriv->sta_hash[i]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+ {
+ ptdls_sta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ if( ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE )
+ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 1);
+ plist = get_next(plist);
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+#endif //CONFIG_TDLS
+
+ pwrpriv->smart_ps = smart_ps;
+ pwrpriv->pwr_mode = ps_mode;
+ pwrpriv->bFwCurrentInPSMode = _TRUE;
+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+#ifdef CONFIG_P2P_PS
+ // Set CTWindow after LPS
+ if(pwdinfo->opp_ps == 1)
+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0);
+#endif // CONFIG_P2P_PS
+#ifdef CONFIG_LPS_LCLK
+ if (pwrpriv->alives == 0)
+ rtw_set_rpwm(padapter, PS_STATE_S0);
+#else
+ rtw_set_rpwm(padapter, PS_STATE_S2);
+#endif
+#ifdef CONFIG_LPS_LCLK
+ _exit_pwrlock(&pwrpriv->lock);
+#endif
+ }
+ //else
+ //{
+ // pwrpriv->pwr_mode = PS_MODE_ACTIVE;
+ //}
+ }
+
+_func_exit_;
+}
+
+
+//
+// Description:
+// Enter the leisure power save mode.
+//
+void LPS_Enter(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+_func_enter_;
+
+// DBG_871X("+LeisurePSEnter\n");
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (padapter->iface_type != IFACE_PORT0)
+ return; /* Skip power saving for concurrent mode port 1*/
+#endif
+
+#ifdef CONFIG_INTEL_PROXIM
+ if(padapter->proximity.proxim_on==_TRUE){
+ return;
+ }
+#endif
+ if ( (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) ||
+ (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) )
+ return;
+
+ if(_TRUE == pwrpriv->bInSuspend )
+ return ;
+
+ if (pwrpriv->bLeisurePs)
+ {
+ // Idle for a while if we connect to AP a while ago.
+ if(pwrpriv->LpsIdleCount >= 2) // 4 Sec
+ {
+ if(pwrpriv->pwr_mode == PS_MODE_ACTIVE)
+ {
+ rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, 2);
+ }
+ }
+ else
+ pwrpriv->LpsIdleCount++;
+ }
+
+// DBG_871X("-LeisurePSEnter\n");
+
+_func_exit_;
+}
+
+
+//
+// Description:
+// Leave the leisure power save mode.
+//
+void LPS_Leave(PADAPTER padapter)
+{
+#define LPS_LEAVE_TIMEOUT_MS 100
+
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ u32 start_time;
+ BOOLEAN bAwake = _FALSE;
+
+_func_enter_;
+
+// DBG_871X("+LeisurePSLeave\n");
+
+ if (pwrpriv->bLeisurePs)
+ {
+ if(pwrpriv->pwr_mode != PS_MODE_ACTIVE)
+ {
+ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0);
+
+ if(pwrpriv->pwr_mode == PS_MODE_ACTIVE)
+ {
+ start_time = rtw_get_current_time();
+ while(1)
+ {
+ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bAwake));
+
+ if(bAwake || padapter->bSurpriseRemoved)
+ break;
+
+ if(rtw_get_passing_time_ms(start_time)>LPS_LEAVE_TIMEOUT_MS)
+ {
+ DBG_871X("Wait for FW LPS leave more than %u ms!!!\n", LPS_LEAVE_TIMEOUT_MS);
+ break;
+ }
+ rtw_usleep_os(100);
+ }
+ }
+ }
+ }
+
+
+// DBG_871X("-LeisurePSLeave\n");
+
+_func_exit_;
+}
+
+#endif
+
+//
+// Description: Leave all power save mode: LPS, FwLPS, IPS if needed.
+// Move code to function by tynli. 2010.03.26.
+//
+void LeaveAllPowerSaveMode(IN PADAPTER Adapter)
+{
+ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
+
+_func_enter_;
+
+ //DBG_871X("%s.....\n",__FUNCTION__);
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+ { //connect
+#ifdef CONFIG_P2P_PS
+ p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, 0);
+#endif // CONFIG_P2P_PS
+#ifdef CONFIG_LPS
+ //DBG_871X("==> leave LPS.......\n");
+ LPS_Leave(Adapter);
+#endif
+ }
+ else
+ {
+ if(Adapter->pwrctrlpriv.rf_pwrstate== rf_off)
+ {
+ #ifdef CONFIG_AUTOSUSPEND
+ if(Adapter->registrypriv.usbss_enable)
+ {
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
+ usb_disable_autosuspend(Adapter->dvobjpriv.pusbdev);
+ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,22) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,34))
+ Adapter->dvobjpriv.pusbdev->autosuspend_disabled = Adapter->bDisableAutosuspend;//autosuspend disabled by the user
+ #endif
+ }
+ else
+ #endif
+ {
+ /*
+ #ifdef CONFIG_IPS
+ if(_FALSE == ips_leave(Adapter))
+ {
+ DBG_871X("======> ips_leave fail.............\n");
+ }
+ #endif
+ */
+ }
+ }
+ }
+
+_func_exit_;
+}
+
+#ifdef CONFIG_LPS_LCLK
+/*
+ * Caller:ISR handler...
+ *
+ * This will be called when CPWM interrupt is up.
+ *
+ * using to update cpwn of drv; and drv willl make a decision to up or down pwr level
+ */
+void cpwm_int_hdl(
+ PADAPTER padapter,
+ struct reportpwrstate_parm *preportpwrstate)
+{
+ struct pwrctrl_priv *pwrpriv;
+
+
+_func_enter_;
+
+ pwrpriv = &padapter->pwrctrlpriv;
+#if 0
+ if (pwrpriv->cpwm_tog == (preportpwrstate->state & PS_TOGGLE)) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("cpwm_int_hdl: tog(old)=0x%02x cpwm(new)=0x%02x toggle bit didn't change!?\n",
+ pwrpriv->cpwm_tog, preportpwrstate->state));
+ goto exit;
+ }
+#endif
+// _enter_pwrlock(&pwrpriv->lock);
+
+ pwrpriv->cpwm = PS_STATE(preportpwrstate->state);
+ pwrpriv->cpwm_tog = preportpwrstate->state & PS_TOGGLE;
+
+ if (pwrpriv->cpwm >= PS_STATE_S2) {
+ if (pwrpriv->alives & CMD_ALIVE)
+ _rtw_up_sema(&padapter->cmdpriv.cmd_queue_sema);
+
+ if (pwrpriv->alives & XMIT_ALIVE)
+ _rtw_up_sema(&padapter->xmitpriv.xmit_sema);
+ }
+
+// _exit_pwrlock(&pwrpriv->lock);
+
+exit:
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("cpwm_int_hdl: cpwm=0x%02x\n", pwrpriv->cpwm));
+
+_func_exit_;
+}
+
+__inline static void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
+{
+ pwrctrl->alives |= tag;
+}
+
+__inline static void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
+{
+ pwrctrl->alives &= ~tag;
+}
+
+/*
+ * Caller: rtw_xmit_thread
+ *
+ * Check if the fw_pwrstate is okay for xmit.
+ * If not (cpwm is less than S3), then the sub-routine
+ * will raise the cpwm to be greater than or equal to S3.
+ *
+ * Calling Context: Passive
+ *
+ * Return Value:
+ * _SUCCESS rtw_xmit_thread can write fifo/txcmd afterwards.
+ * _FAIL rtw_xmit_thread can not do anything.
+ */
+s32 rtw_register_tx_alive(PADAPTER padapter)
+{
+ s32 res;
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ res = _SUCCESS;
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ register_task_alive(pwrctrl, XMIT_ALIVE);
+
+ if (pwrctrl->bFwCurrentInPSMode == _TRUE)
+ {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("rtw_register_tx_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+
+ if (pwrctrl->cpwm < PS_STATE_S2) {
+ if (pwrctrl->rpwm < PS_STATE_S2)
+ rtw_set_rpwm(padapter, PS_STATE_S2);
+ res = _FAIL;
+ }
+ }
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+
+ return res;
+}
+
+/*
+ * Caller: rtw_cmd_thread
+ *
+ * Check if the fw_pwrstate is okay for issuing cmd.
+ * If not (cpwm should be is less than S2), then the sub-routine
+ * will raise the cpwm to be greater than or equal to S2.
+ *
+ * Calling Context: Passive
+ *
+ * Return Value:
+ * _SUCCESS rtw_cmd_thread can issue cmds to firmware afterwards.
+ * _FAIL rtw_cmd_thread can not do anything.
+ */
+s32 rtw_register_cmd_alive(PADAPTER padapter)
+{
+ s32 res;
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ res = _SUCCESS;
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ register_task_alive(pwrctrl, CMD_ALIVE);
+
+ if (pwrctrl->bFwCurrentInPSMode == _TRUE)
+ {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_register_cmd_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+
+ if (pwrctrl->cpwm < PS_STATE_S2) {
+ if (pwrctrl->rpwm < PS_STATE_S2)
+ rtw_set_rpwm(padapter, PS_STATE_S2);
+ res = _FAIL;
+ }
+ }
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+
+ return res;
+}
+
+/*
+ * Caller: rx_isr
+ *
+ * Calling Context: Dispatch/ISR
+ *
+ * Return Value:
+ * _SUCCESS
+ * _FAIL
+ */
+s32 rtw_register_rx_alive(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ register_task_alive(pwrctrl, RECV_ALIVE);
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_register_rx_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+/*
+ * Caller: evt_isr or evt_thread
+ *
+ * Calling Context: Dispatch/ISR or Passive
+ *
+ * Return Value:
+ * _SUCCESS
+ * _FAIL
+ */
+s32 rtw_register_evt_alive(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ register_task_alive(pwrctrl, EVT_ALIVE);
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_register_evt_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+/*
+ * Caller: ISR
+ *
+ * If ISR's txdone,
+ * No more pkts for TX,
+ * Then driver shall call this fun. to power down firmware again.
+ */
+void rtw_unregister_tx_alive(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ unregister_task_alive(pwrctrl, XMIT_ALIVE);
+
+ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) &&
+ (pwrctrl->bFwCurrentInPSMode == _TRUE))
+ {
+ if ((pwrctrl->alives == 0) &&
+ (pwrctrl->cpwm > PS_STATE_S0))
+ {
+ rtw_set_rpwm(padapter, PS_STATE_S0);
+ }
+
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_unregister_tx_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+ }
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+}
+
+/*
+ * Caller: ISR
+ *
+ * If all commands have been done,
+ * and no more command to do,
+ * then driver shall call this fun. to power down firmware again.
+ */
+void rtw_unregister_cmd_alive(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ unregister_task_alive(pwrctrl, CMD_ALIVE);
+
+ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) &&
+ (pwrctrl->bFwCurrentInPSMode == _TRUE))
+ {
+ if ((pwrctrl->alives == 0) &&
+ (pwrctrl->cpwm > PS_STATE_S0))
+ {
+ rtw_set_rpwm(padapter, PS_STATE_S0);
+ }
+
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_unregister_cmd_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+ }
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+}
+
+/*
+ * Caller: ISR
+ */
+void rtw_unregister_rx_alive(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ _enter_pwrlock(&pwrctrl->lock);
+
+ unregister_task_alive(pwrctrl, RECV_ALIVE);
+
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_unregister_rx_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+}
+
+void rtw_unregister_evt_alive(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrl;
+
+_func_enter_;
+
+ pwrctrl = &padapter->pwrctrlpriv;
+
+ unregister_task_alive(pwrctrl, EVT_ALIVE);
+
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_unregister_evt_alive: cpwm=0x%02x alives=0x%08x\n",
+ pwrctrl->cpwm, pwrctrl->alives));
+
+ _exit_pwrlock(&pwrctrl->lock);
+
+_func_exit_;
+}
+#endif /* CONFIG_LPS_LCLK */
+
+#ifdef CONFIG_RESUME_IN_WORKQUEUE
+static void resume_workitem_callback(struct work_struct *work);
+#endif //CONFIG_RESUME_IN_WORKQUEUE
+
+void rtw_init_pwrctrl_priv(PADAPTER padapter)
+{
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+#ifdef PLATFORM_WINDOWS
+ pwrctrlpriv->pnp_current_pwr_state=NdisDeviceStateD0;
+#endif
+
+ _init_pwrlock(&pwrctrlpriv->lock);
+ pwrctrlpriv->rf_pwrstate = rf_on;
+ pwrctrlpriv->ips_enter_cnts=0;
+ pwrctrlpriv->ips_leave_cnts=0;
+
+ pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
+ pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
+
+ pwrctrlpriv->pwr_state_check_interval = 2000;
+ pwrctrlpriv->pwr_state_check_cnts = 0;
+ pwrctrlpriv->bInternalAutoSuspend = _FALSE;
+ pwrctrlpriv->bInSuspend = _FALSE;
+ pwrctrlpriv->bkeepfwalive = _FALSE;
+
+#ifdef CONFIG_AUTOSUSPEND
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ pwrctrlpriv->pwr_state_check_interval = (pwrctrlpriv->bHWPwrPindetect) ?1000:2000;
+#endif
+#endif
+
+ pwrctrlpriv->LpsIdleCount = 0;
+ //pwrctrlpriv->FWCtrlPSMode =padapter->registrypriv.power_mgnt;// PS_MODE_MIN;
+ pwrctrlpriv->power_mgnt =padapter->registrypriv.power_mgnt;// PS_MODE_MIN;
+ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?_TRUE:_FALSE;
+
+ pwrctrlpriv->bFwCurrentInPSMode = _FALSE;
+
+ pwrctrlpriv->cpwm = PS_STATE_S4;
+
+ pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
+
+
+ pwrctrlpriv->smart_ps = 0;
+
+ pwrctrlpriv->tog = 0x80;
+
+#ifdef PLATFORM_LINUX
+ _init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter);
+#endif
+
+ #ifdef CONFIG_RESUME_IN_WORKQUEUE
+ _init_workitem(&pwrctrlpriv->resume_work, resume_workitem_callback, NULL);
+ pwrctrlpriv->rtw_workqueue = create_singlethread_workqueue("rtw_workqueue");
+ #endif //CONFIG_RESUME_IN_WORKQUEUE
+
+ #if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER)
+ pwrctrlpriv->early_suspend.suspend = NULL;
+ rtw_register_early_suspend(pwrctrlpriv);
+ #endif //CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER
+
+
+_func_exit_;
+
+}
+
+
+void rtw_free_pwrctrl_priv(PADAPTER adapter)
+{
+ struct pwrctrl_priv *pwrctrlpriv = &adapter->pwrctrlpriv;
+
+_func_enter_;
+
+ //_rtw_memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv));
+
+
+ #ifdef CONFIG_RESUME_IN_WORKQUEUE
+ if (pwrctrlpriv->rtw_workqueue) {
+ flush_workqueue(pwrctrlpriv->rtw_workqueue);
+ destroy_workqueue(pwrctrlpriv->rtw_workqueue);
+ }
+ #endif
+
+
+ #if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER)
+ rtw_unregister_early_suspend(pwrctrlpriv);
+ #endif //CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER
+
+ _free_pwrlock(&pwrctrlpriv->lock);
+
+_func_exit_;
+}
+
+#ifdef CONFIG_RESUME_IN_WORKQUEUE
+#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
+extern int rtw_resume_process(_adapter *padapter);
+#endif
+static void resume_workitem_callback(struct work_struct *work)
+{
+ struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, resume_work);
+ _adapter *adapter = container_of(pwrpriv, _adapter, pwrctrlpriv);
+
+ DBG_871X("%s\n",__FUNCTION__);
+
+ #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
+ rtw_resume_process(adapter);
+ #endif
+
+}
+
+void rtw_resume_in_workqueue(struct pwrctrl_priv *pwrpriv)
+{
+ // accquire system's suspend lock preventing from falliing asleep while resume in workqueue
+ rtw_lock_suspend();
+
+ #if 1
+ queue_work(pwrpriv->rtw_workqueue, &pwrpriv->resume_work);
+ #else
+ _set_workitem(&pwrpriv->resume_work);
+ #endif
+}
+#endif //CONFIG_RESUME_IN_WORKQUEUE
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
+extern int rtw_resume_process(_adapter *padapter);
+#endif
+static void rtw_early_suspend(struct early_suspend *h)
+{
+ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
+ DBG_871X("%s\n",__FUNCTION__);
+
+ //jeff: do nothing but set do_late_resume to false
+ pwrpriv->do_late_resume = _FALSE;
+}
+
+static void rtw_late_resume(struct early_suspend *h)
+{
+ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
+ _adapter *adapter = container_of(pwrpriv, _adapter, pwrctrlpriv);
+
+ DBG_871X("%s\n",__FUNCTION__);
+ if(pwrpriv->do_late_resume) {
+ #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
+ rtw_resume_process(adapter);
+ pwrpriv->do_late_resume = _FALSE;
+ #endif
+ }
+}
+
+void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv)
+{
+ DBG_871X("%s\n", __FUNCTION__);
+
+ //jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit
+ pwrpriv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20;
+ pwrpriv->early_suspend.suspend = rtw_early_suspend;
+ pwrpriv->early_suspend.resume = rtw_late_resume;
+ register_early_suspend(&pwrpriv->early_suspend);
+
+
+}
+
+void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv)
+{
+ DBG_871X("%s\n", __FUNCTION__);
+
+ pwrpriv->do_late_resume = _FALSE;
+
+ if (pwrpriv->early_suspend.suspend)
+ unregister_early_suspend(&pwrpriv->early_suspend);
+
+ pwrpriv->early_suspend.suspend = NULL;
+ pwrpriv->early_suspend.resume = NULL;
+}
+#endif //CONFIG_HAS_EARLYSUSPEND
+
+#ifdef CONFIG_ANDROID_POWER
+#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
+extern int rtw_resume_process(PADAPTER padapter);
+#endif
+static void rtw_early_suspend(android_early_suspend_t *h)
+{
+ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
+ DBG_871X("%s\n",__FUNCTION__);
+
+ //jeff: do nothing but set do_late_resume to false
+ pwrpriv->do_late_resume = _FALSE;
+}
+
+static void rtw_late_resume(android_early_suspend_t *h)
+{
+ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
+ _adapter *adapter = container_of(pwrpriv, _adapter, pwrctrlpriv);
+
+ DBG_871X("%s\n",__FUNCTION__);
+ if(pwrpriv->do_late_resume) {
+ #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
+ rtw_resume_process(adapter);
+ pwrpriv->do_late_resume = _FALSE;
+ #endif
+ }
+}
+
+void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv)
+{
+ DBG_871X("%s\n", __FUNCTION__);
+
+ //jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit
+ pwrpriv->early_suspend.level = ANDROID_EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20;
+ pwrpriv->early_suspend.suspend = rtw_early_suspend;
+ pwrpriv->early_suspend.resume = rtw_late_resume;
+ android_register_early_suspend(&pwrpriv->early_suspend);
+}
+
+void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv)
+{
+ DBG_871X("%s\n", __FUNCTION__);
+
+ pwrpriv->do_late_resume = _FALSE;
+
+ if (pwrpriv->early_suspend.suspend)
+ android_unregister_early_suspend(&pwrpriv->early_suspend);
+
+ pwrpriv->early_suspend.suspend = NULL;
+ pwrpriv->early_suspend.resume = NULL;
+}
+#endif //CONFIG_ANDROID_POWER
+
+u8 rtw_interface_ps_func(_adapter *padapter,HAL_INTF_PS_FUNC efunc_id,u8* val)
+{
+ u8 bResult = _TRUE;
+ if(padapter->HalFunc.interface_ps_func)
+ {
+ bResult = padapter->HalFunc.interface_ps_func(padapter,efunc_id,val);
+ }
+ return bResult;
+}
+
+/*
+* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
+* @adapter: pointer to _adapter structure
+*
+* Return _SUCCESS or _FAIL
+*/
+int _rtw_pwr_wakeup(_adapter *padapter, const char *caller)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ int ret = _SUCCESS;
+
+ //System suspend is not allowed to wakeup
+ if((pwrpriv->bInternalAutoSuspend == _FALSE) && (_TRUE == pwrpriv->bInSuspend )){
+ ret = _FAIL;
+ goto exit;
+ }
+
+ //I think this should be check in IPS, LPS, autosuspend functions...
+ //if( pwrpriv->power_mgnt == PS_MODE_ACTIVE ) {
+ // goto exit;
+ //}
+
+ //block???
+ if((pwrpriv->bInternalAutoSuspend == _TRUE) && (padapter->net_closed == _TRUE)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ //I think this should be check in IPS, LPS, autosuspend functions...
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+ {
+ ret = _SUCCESS;
+ goto exit;
+ }
+
+ if(rf_off == pwrpriv->rf_pwrstate )
+ {
+#ifdef CONFIG_USB_HCI
+#ifdef CONFIG_AUTOSUSPEND
+ if(pwrpriv->brfoffbyhw==_TRUE)
+ {
+ DBG_8192C("hw still in rf_off state ...........\n");
+ ret = _FAIL;
+ goto exit;
+ }
+ else if(padapter->registrypriv.usbss_enable)
+ {
+ DBG_8192C("\n %s call autoresume_enter....\n",__FUNCTION__);
+ if(_FAIL == autoresume_enter(padapter))
+ {
+ DBG_8192C("======> autoresume fail.............\n");
+ ret = _FAIL;
+ goto exit;
+ }
+ }
+ else
+#endif
+#endif
+ {
+#ifdef CONFIG_IPS
+ DBG_8192C("\n %s call ips_leave....\n",__FUNCTION__);
+ if(_FAIL == ips_leave(padapter))
+ {
+ DBG_8192C("======> ips_leave fail.............\n");
+ ret = _FAIL;
+ goto exit;
+ }
+#endif
+ }
+ }else {
+ //Jeff: reset timer to avoid falling ips or selective suspend soon
+ if(pwrpriv->bips_processing == _FALSE)
+ rtw_set_pwr_state_check_timer(pwrpriv);
+ }
+
+ //TODO: the following checking need to be merged...
+ if(padapter->bDriverStopped
+ || !padapter->bup
+ || !padapter->hw_init_completed
+ ){
+ DBG_8192C("%s: bDriverStopped=%d, bup=%d, hw_init_completed=%u\n"
+ , caller
+ , padapter->bDriverStopped
+ , padapter->bup
+ , padapter->hw_init_completed);
+ ret= _FALSE;
+ goto exit;
+ }
+
+exit:
+ return ret;
+
+}
+
+int rtw_pm_set_lps(_adapter *padapter, u8 mode)
+{
+ int ret = 0;
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+ if ( mode < PS_MODE_NUM )
+ {
+ if(pwrctrlpriv->power_mgnt !=mode)
+ {
+ if(PS_MODE_ACTIVE == mode)
+ {
+ LeaveAllPowerSaveMode(padapter);
+ }
+ else
+ {
+ pwrctrlpriv->LpsIdleCount = 2;
+ }
+ pwrctrlpriv->power_mgnt = mode;
+ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?_TRUE:_FALSE;
+ }
+ }
+ else
+ {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int rtw_pm_set_ips(_adapter *padapter, u8 mode)
+{
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+ if( mode == IPS_NORMAL || mode == IPS_LEVEL_2 ) {
+ rtw_ips_mode_req(pwrctrlpriv, mode);
+ rtw_set_pwr_state_check_timer(pwrctrlpriv);
+ DBG_871X("%s %s\n", __FUNCTION__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2");
+ return 0;
+ }
+ else if(mode ==IPS_NONE){
+ rtw_ips_mode_req(pwrctrlpriv, mode);
+ DBG_871X("%s %s\n", __FUNCTION__, "IPS_NONE");
+ if(_FAIL == rtw_pwr_wakeup(padapter))
+ return -EFAULT;
+ }
+ else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+