| /* |
| * Copyright (c) 2007-2008 Atheros Communications Inc. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /** |
| * The power saving manager is to save the power as much as possible. |
| * Generally speaking, it controls: |
| * |
| * - when to sleep |
| * - |
| * |
| */ |
| #include "cprecomp.h" |
| |
| void zfPowerSavingMgrInit(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| wd->sta.powerSaveMode = ZM_STA_PS_NONE; |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_ACTIVE; |
| wd->sta.psMgr.isSleepAllowed = 0; |
| wd->sta.psMgr.maxSleepPeriods = 1; |
| wd->sta.psMgr.ticks = 0; |
| wd->sta.psMgr.sleepAllowedtick = 0; |
| } |
| |
| static u16_t zfPowerSavingMgrHandlePsNone(zdev_t* dev, u8_t *isWakeUpRequired) |
| { |
| u16_t ret = 0; |
| zmw_get_wlan_dev(dev); |
| |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| *isWakeUpRequired = 0; |
| break; |
| |
| case ZM_PS_MSG_STATE_T1: |
| case ZM_PS_MSG_STATE_T2: |
| case ZM_PS_MSG_STATE_SLEEP: |
| default: |
| *isWakeUpRequired = 1; |
| zm_debug_msg0("zfPowerSavingMgrHandlePsNone: Wake up now\n"); |
| if ( zfStaIsConnected(dev) ) |
| { |
| zm_debug_msg0("zfPowerSavingMgrOnHandleT1 send Null data\n"); |
| //zfSendNullData(dev, 0); |
| ret = 1; |
| } |
| |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_ACTIVE; |
| break; |
| } |
| return ret; |
| } |
| |
| static void zfPowerSavingMgrHandlePs(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| //zm_debug_msg0("zfPowerSavingMgrHandlePs: Prepare to sleep...\n"); |
| //wd->sta.psMgr.state = ZM_PS_MSG_STATE_T1; |
| break; |
| |
| case ZM_PS_MSG_STATE_T1: |
| case ZM_PS_MSG_STATE_T2: |
| case ZM_PS_MSG_STATE_SLEEP: |
| default: |
| break; |
| } |
| } |
| |
| void zfPowerSavingMgrSetMode(zdev_t* dev, u8_t mode) |
| { |
| u16_t sendNull = 0; |
| u8_t isWakeUpRequired = 0; |
| |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| zm_debug_msg1("mode = ", mode); |
| |
| if (mode > ZM_STA_PS_LIGHT) |
| { |
| zm_debug_msg0("return - wrong power save mode"); |
| return; |
| } |
| |
| zmw_enter_critical_section(dev); |
| |
| #if 1 |
| switch(mode) |
| { |
| case ZM_STA_PS_NONE: |
| sendNull = zfPowerSavingMgrHandlePsNone(dev, &isWakeUpRequired); |
| break; |
| |
| case ZM_STA_PS_FAST: |
| case ZM_STA_PS_LIGHT: |
| wd->sta.psMgr.maxSleepPeriods = 1; |
| zfPowerSavingMgrHandlePs(dev); |
| break; |
| |
| case ZM_STA_PS_MAX: |
| wd->sta.psMgr.maxSleepPeriods = ZM_PS_MAX_SLEEP_PERIODS; |
| zfPowerSavingMgrHandlePs(dev); |
| break; |
| } |
| #else |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| if ( mode != ZM_STA_PS_NONE ) |
| { |
| zm_debug_msg0("zfPowerSavingMgrSetMode: switch from ZM_PS_MSG_STATE_ACTIVE to ZM_PS_MSG_STATE_T1\n"); |
| // Stall the TX & start to wait the pending TX to be completed |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_T1; |
| } |
| break; |
| |
| case ZM_PS_MSG_STATE_SLEEP: |
| break; |
| } |
| #endif |
| |
| wd->sta.powerSaveMode = mode; |
| zmw_leave_critical_section(dev); |
| |
| if ( isWakeUpRequired ) |
| { |
| zfHpPowerSaveSetState(dev, 0); |
| wd->sta.psMgr.tempWakeUp = 0; |
| } |
| |
| if ( zfStaIsConnected(dev) |
| && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ) |
| { |
| switch(mode) |
| { |
| case ZM_STA_PS_NONE: |
| zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); |
| break; |
| |
| case ZM_STA_PS_FAST: |
| case ZM_STA_PS_MAX: |
| case ZM_STA_PS_LIGHT: |
| zfHpPowerSaveSetMode(dev, 0, 1, wd->beaconInterval); |
| break; |
| |
| default: |
| zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); |
| break; |
| } |
| } |
| |
| if (sendNull == 1) |
| { |
| zfSendNullData(dev, 0); |
| } |
| |
| return; |
| } |
| |
| static void zfPowerSavingMgrNotifyPSToAP(zdev_t *dev) |
| { |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| if ( (wd->sta.psMgr.tempWakeUp != 1)&& |
| (wd->sta.psMgr.lastTxUnicastFrm != wd->commTally.txUnicastFrm || |
| wd->sta.psMgr.lastTxBroadcastFrm != wd->commTally.txBroadcastFrm || |
| wd->sta.psMgr.lastTxMulticastFrm != wd->commTally.txMulticastFrm) ) |
| { |
| zmw_enter_critical_section(dev); |
| wd->sta.psMgr.lastTxUnicastFrm = wd->commTally.txUnicastFrm; |
| wd->sta.psMgr.lastTxBroadcastFrm = wd->commTally.txBroadcastFrm; |
| wd->sta.psMgr.lastTxMulticastFrm = wd->commTally.txMulticastFrm; |
| zmw_leave_critical_section(dev); |
| |
| zfSendNullData(dev, 1); |
| } |
| } |
| |
| static void zfPowerSavingMgrOnHandleT1(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| // If the tx Q is not empty...return |
| if ( zfIsVtxqEmpty(dev) == FALSE ) |
| { |
| return; |
| } |
| |
| zm_debug_msg0("VtxQ is empty now...Check if HAL TXQ is empty\n"); |
| |
| // The the HAL TX Q is not empty...return |
| if ( zfHpGetFreeTxdCount(dev) != zfHpGetMaxTxdCount(dev) ) |
| { |
| return; |
| } |
| |
| zm_debug_msg0("HAL TXQ is empty now...Could go to sleep...\n"); |
| |
| zmw_enter_critical_section(dev); |
| |
| if (wd->sta.powerSaveMode == ZM_STA_PS_LIGHT) |
| { |
| if (wd->sta.ReceivedPktRatePerSecond > 200) |
| { |
| zmw_leave_critical_section(dev); |
| return; |
| } |
| |
| if ( zfStaIsConnected(dev) |
| && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ) |
| { |
| if (wd->sta.psMgr.sleepAllowedtick) { |
| wd->sta.psMgr.sleepAllowedtick--; |
| zmw_leave_critical_section(dev); |
| return; |
| } |
| } |
| } |
| |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_T2; |
| |
| zmw_leave_critical_section(dev); |
| |
| // Send the Null pkt to AP to notify that I'm going to sleep |
| if ( zfStaIsConnected(dev) ) |
| { |
| zm_debug_msg0("zfPowerSavingMgrOnHandleT1 send Null data\n"); |
| zfPowerSavingMgrNotifyPSToAP(dev); |
| } |
| |
| // Stall the TX now |
| // zfTxEngineStop(dev); |
| } |
| |
| static void zfPowerSavingMgrOnHandleT2(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| // Wait until the Null pkt is transmitted |
| if ( zfHpGetFreeTxdCount(dev) != zfHpGetMaxTxdCount(dev) ) |
| { |
| return; |
| } |
| |
| zmw_enter_critical_section(dev); |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_SLEEP; |
| wd->sta.psMgr.lastTxUnicastFrm = wd->commTally.txUnicastFrm; |
| wd->sta.psMgr.lastTxBroadcastFrm = wd->commTally.txBroadcastFrm; |
| wd->sta.psMgr.lastTxMulticastFrm = wd->commTally.txMulticastFrm; |
| zmw_leave_critical_section(dev); |
| |
| // Let CHIP sleep now |
| zm_debug_msg0("zfPowerSavingMgrOnHandleT2 zzzz....\n"); |
| zfHpPowerSaveSetState(dev, 1); |
| wd->sta.psMgr.tempWakeUp = 0; |
| } |
| |
| u8_t zfPowerSavingMgrIsSleeping(zdev_t *dev) |
| { |
| u8_t isSleeping = FALSE; |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| zmw_enter_critical_section(dev); |
| if ( wd->sta.psMgr.state == ZM_PS_MSG_STATE_SLEEP || |
| wd->sta.psMgr.state == ZM_PS_MSG_STATE_T2) |
| { |
| isSleeping = TRUE; |
| } |
| zmw_leave_critical_section(dev); |
| return isSleeping; |
| } |
| |
| static u8_t zfPowerSavingMgrIsIdle(zdev_t *dev) |
| { |
| u8_t isIdle = 0; |
| |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| zmw_enter_critical_section(dev); |
| |
| if ( zfStaIsConnected(dev) && wd->sta.psMgr.isSleepAllowed == 0 ) |
| { |
| goto done; |
| } |
| |
| if ( wd->sta.bChannelScan ) |
| { |
| goto done; |
| } |
| |
| if ( zfStaIsConnecting(dev) ) |
| { |
| goto done; |
| } |
| |
| if (wd->sta.powerSaveMode == ZM_STA_PS_LIGHT) |
| { |
| if (wd->sta.ReceivedPktRatePerSecond > 200) |
| { |
| goto done; |
| } |
| |
| if ( zfStaIsConnected(dev) |
| && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ) |
| { |
| if (wd->sta.psMgr.sleepAllowedtick) { |
| wd->sta.psMgr.sleepAllowedtick--; |
| goto done; |
| } |
| } |
| } |
| |
| isIdle = 1; |
| |
| done: |
| zmw_leave_critical_section(dev); |
| |
| if ( zfIsVtxqEmpty(dev) == FALSE ) |
| { |
| isIdle = 0; |
| } |
| |
| return isIdle; |
| } |
| |
| static void zfPowerSavingMgrSleepIfIdle(zdev_t *dev) |
| { |
| u8_t isIdle; |
| |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| isIdle = zfPowerSavingMgrIsIdle(dev); |
| |
| if ( isIdle == 0 ) |
| { |
| return; |
| } |
| |
| zmw_enter_critical_section(dev); |
| |
| switch(wd->sta.powerSaveMode) |
| { |
| case ZM_STA_PS_NONE: |
| break; |
| |
| case ZM_STA_PS_MAX: |
| case ZM_STA_PS_FAST: |
| case ZM_STA_PS_LIGHT: |
| zm_debug_msg0("zfPowerSavingMgrSleepIfIdle: IDLE so slep now...\n"); |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_T1; |
| break; |
| } |
| |
| zmw_leave_critical_section(dev); |
| } |
| |
| static void zfPowerSavingMgrDisconnectMain(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| #ifdef ZM_ENABLE_DISCONNECT_PS |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| zfPowerSavingMgrSleepIfIdle(dev); |
| break; |
| |
| case ZM_PS_MSG_STATE_SLEEP: |
| break; |
| |
| case ZM_PS_MSG_STATE_T1: |
| zfPowerSavingMgrOnHandleT1(dev); |
| break; |
| |
| case ZM_PS_MSG_STATE_T2: |
| zfPowerSavingMgrOnHandleT2(dev); |
| break; |
| } |
| #else |
| zfPowerSavingMgrWakeup(dev); |
| #endif |
| } |
| |
| static void zfPowerSavingMgrInfraMain(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| zfPowerSavingMgrSleepIfIdle(dev); |
| break; |
| |
| case ZM_PS_MSG_STATE_SLEEP: |
| break; |
| |
| case ZM_PS_MSG_STATE_T1: |
| zfPowerSavingMgrOnHandleT1(dev); |
| break; |
| |
| case ZM_PS_MSG_STATE_T2: |
| zfPowerSavingMgrOnHandleT2(dev); |
| break; |
| } |
| } |
| |
| void zfPowerSavingMgrAtimWinExpired(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| //printk("zfPowerSavingMgrAtimWinExpired #1\n"); |
| if ( wd->sta.powerSaveMode == ZM_STA_PS_NONE ) |
| { |
| return; |
| } |
| |
| //printk("zfPowerSavingMgrAtimWinExpired #2\n"); |
| // if we received any ATIM window from the others to indicate we have buffered data |
| // at the other station, we can't go to sleep |
| if ( wd->sta.recvAtim ) |
| { |
| wd->sta.recvAtim = 0; |
| zm_debug_msg0("Can't sleep due to receving ATIM window!"); |
| return; |
| } |
| |
| // if we are the one to tx beacon during last beacon interval. we can't go to sleep |
| // since we need to be alive to respond the probe request! |
| if ( wd->sta.txBeaconInd ) |
| { |
| zm_debug_msg0("Can't sleep due to just transmit a beacon!"); |
| return; |
| } |
| |
| // If we buffer any data for the other stations. we could not go to sleep |
| if ( wd->sta.ibssPrevPSDataCount != 0 ) |
| { |
| zm_debug_msg0("Can't sleep due to buffering data for the others!"); |
| return; |
| } |
| |
| // before sleeping, we still need to notify the others by transmitting null |
| // pkt with power mgmt bit turned on. |
| zfPowerSavingMgrOnHandleT1(dev); |
| } |
| |
| static void zfPowerSavingMgrIBSSMain(zdev_t* dev) |
| { |
| // wait for the end of |
| // if need to wait to know if we are the one to transmit the beacon |
| // during the beacon interval. If it's me, we can't go to sleep. |
| |
| zmw_get_wlan_dev(dev); |
| |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| case ZM_PS_MSG_STATE_SLEEP: |
| case ZM_PS_MSG_STATE_T1: |
| break; |
| |
| case ZM_PS_MSG_STATE_T2: |
| zfPowerSavingMgrOnHandleT2(dev); |
| break; |
| } |
| |
| return; |
| } |
| |
| #if 1 |
| void zfPowerSavingMgrMain(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| switch (wd->sta.adapterState) |
| { |
| case ZM_STA_STATE_DISCONNECT: |
| zfPowerSavingMgrDisconnectMain(dev); |
| break; |
| case ZM_STA_STATE_CONNECTED: |
| { |
| if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) { |
| zfPowerSavingMgrInfraMain(dev); |
| } else if (wd->wlanMode == ZM_MODE_IBSS) { |
| zfPowerSavingMgrIBSSMain(dev); |
| } |
| } |
| break; |
| case ZM_STA_STATE_CONNECTING: |
| default: |
| break; |
| } |
| } |
| #else |
| void zfPowerSavingMgrMain(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE ) |
| { |
| return; |
| } |
| |
| switch(wd->sta.psMgr.state) |
| { |
| case ZM_PS_MSG_STATE_ACTIVE: |
| goto check_sleep; |
| break; |
| |
| case ZM_PS_MSG_STATE_SLEEP: |
| goto sleeping; |
| break; |
| |
| case ZM_PS_MSG_STATE_T1: |
| zfPowerSavingMgrOnHandleT1(dev); |
| break; |
| |
| case ZM_PS_MSG_STATE_T2: |
| zfPowerSavingMgrOnHandleT2(dev); |
| break; |
| } |
| |
| return; |
| |
| sleeping: |
| return; |
| |
| check_sleep: |
| zfPowerSavingMgrSleepIfIdle(dev); |
| return; |
| } |
| #endif |
| |
| #ifdef ZM_ENABLE_POWER_SAVE |
| void zfPowerSavingMgrWakeup(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| //zm_debug_msg0("zfPowerSavingMgrWakeup"); |
| |
| //if ( wd->sta.psMgr.state != ZM_PS_MSG_STATE_ACTIVE && ( zfPowerSavingMgrIsIdle(dev) == 0 )) |
| if ( wd->sta.psMgr.state != ZM_PS_MSG_STATE_ACTIVE ) |
| { |
| zmw_enter_critical_section(dev); |
| |
| wd->sta.psMgr.isSleepAllowed = 0; |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_ACTIVE; |
| |
| if ( wd->sta.powerSaveMode > ZM_STA_PS_NONE ) |
| wd->sta.psMgr.tempWakeUp = 1; |
| |
| zmw_leave_critical_section(dev); |
| |
| // Wake up the CHIP now!! |
| zfHpPowerSaveSetState(dev, 0); |
| } |
| } |
| #else |
| void zfPowerSavingMgrWakeup(zdev_t* dev) |
| { |
| } |
| #endif |
| |
| void zfPowerSavingMgrProcessBeacon(zdev_t* dev, zbuf_t* buf) |
| { |
| u8_t length, bitmap; |
| u16_t offset, n1, n2, q, r; |
| zbuf_t* psBuf; |
| |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| if ( wd->sta.powerSaveMode == ZM_STA_PS_NONE ) |
| //if ( wd->sta.psMgr.state != ZM_PS_MSG_STATE_SLEEP ) |
| { |
| return; |
| } |
| |
| wd->sta.psMgr.isSleepAllowed = 1; |
| |
| if ( (offset=zfFindElement(dev, buf, ZM_WLAN_EID_TIM)) != 0xffff ) |
| { |
| length = zmw_rx_buf_readb(dev, buf, offset+1); |
| |
| if ( length > 3 ) |
| { |
| n1 = zmw_rx_buf_readb(dev, buf, offset+4) & (~ZM_BIT_0); |
| n2 = length + n1 - 4; |
| q = wd->sta.aid >> 3; |
| r = wd->sta.aid & 7; |
| |
| if ((q >= n1) && (q <= n2)) |
| { |
| bitmap = zmw_rx_buf_readb(dev, buf, offset+5+q-n1); |
| |
| if ( (bitmap >> r) & ZM_BIT_0 ) |
| { |
| //if ( wd->sta.powerSaveMode == ZM_STA_PS_FAST ) |
| if ( 0 ) |
| { |
| wd->sta.psMgr.state = ZM_PS_MSG_STATE_S1; |
| //zfSendPSPoll(dev); |
| zfSendNullData(dev, 0); |
| } |
| else |
| { |
| if ((wd->sta.qosInfo&0xf) != 0xf) |
| { |
| /* send ps-poll */ |
| //printk("zfSendPSPoll #1\n"); |
| |
| wd->sta.psMgr.isSleepAllowed = 0; |
| |
| switch (wd->sta.powerSaveMode) |
| { |
| case ZM_STA_PS_MAX: |
| case ZM_STA_PS_FAST: |
| //zm_debug_msg0("wake up and send PS-Poll\n"); |
| zfSendPSPoll(dev); |
| break; |
| case ZM_STA_PS_LIGHT: |
| zm_debug_msg0("wake up and send null data\n"); |
| |
| zmw_enter_critical_section(dev); |
| wd->sta.psMgr.sleepAllowedtick = 400; |
| zmw_leave_critical_section(dev); |
| |
| zfSendNullData(dev, 0); |
| break; |
| } |
| |
| wd->sta.psMgr.tempWakeUp = 0; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| while ((psBuf = zfQueueGet(dev, wd->sta.uapsdQ)) != NULL) |
| { |
| zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); |
| } |
| |
| //printk("zfPowerSavingMgrProcessBeacon #1\n"); |
| zfPowerSavingMgrMain(dev); |
| } |
| |
| void zfPowerSavingMgrConnectNotify(zdev_t *dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) |
| { |
| switch(wd->sta.powerSaveMode) |
| { |
| case ZM_STA_PS_NONE: |
| zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); |
| break; |
| |
| case ZM_STA_PS_FAST: |
| case ZM_STA_PS_MAX: |
| case ZM_STA_PS_LIGHT: |
| zfHpPowerSaveSetMode(dev, 0, 1, wd->beaconInterval); |
| break; |
| |
| default: |
| zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); |
| break; |
| } |
| } |
| } |
| |
| void zfPowerSavingMgrPreTBTTInterrupt(zdev_t *dev) |
| { |
| zmw_get_wlan_dev(dev); |
| zmw_declare_for_critical_section(); |
| |
| /* disable TBTT interrupt when change from connection to disconnect */ |
| if (zfStaIsDisconnect(dev)) { |
| zfHpPowerSaveSetMode(dev, 0, 0, 0); |
| zfPowerSavingMgrWakeup(dev); |
| return; |
| } |
| |
| zmw_enter_critical_section(dev); |
| wd->sta.psMgr.ticks++; |
| |
| if ( wd->sta.psMgr.ticks < wd->sta.psMgr.maxSleepPeriods ) |
| { |
| zmw_leave_critical_section(dev); |
| return; |
| } |
| else |
| { |
| wd->sta.psMgr.ticks = 0; |
| } |
| |
| zmw_leave_critical_section(dev); |
| |
| zfPowerSavingMgrWakeup(dev); |
| } |
| |
| /* Leave an empty line below to remove warning message on some compiler */ |
| |