1 /* 2 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * 20 * File: power.c 21 * 22 * Purpose: Handles 802.11 power management functions 23 * 24 * Author: Lyndon Chen 25 * 26 * Date: July 17, 2002 27 * 28 * Functions: 29 * PSvEnablePowerSaving - Enable Power Saving Mode 30 * PSvDiasblePowerSaving - Disable Power Saving Mode 31 * PSbConsiderPowerDown - Decide if we can Power Down 32 * PSvSendPSPOLL - Send PS-POLL packet 33 * PSbSendNullPacket - Send Null packet 34 * PSbIsNextTBTTWakeUp - Decide if we need to wake up at next Beacon 35 * 36 * Revision History: 37 * 38 */ 39 40 #include "mac.h" 41 #include "device.h" 42 #include "wmgr.h" 43 #include "power.h" 44 #include "wcmd.h" 45 #include "rxtx.h" 46 #include "card.h" 47 #include "control.h" 48 #include "rndis.h" 49 50 static int msglevel = MSG_LEVEL_INFO; 51 52 /* 53 * 54 * Routine Description: 55 * Enable hw power saving functions 56 * 57 * Return Value: 58 * None. 59 * 60 */ 61 62 void PSvEnablePowerSaving(struct vnt_private *pDevice, u16 wListenInterval) 63 { 64 struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; 65 u16 wAID = pMgmt->wCurrAID | BIT14 | BIT15; 66 67 /* set period of power up before TBTT */ 68 MACvWriteWord(pDevice, MAC_REG_PWBT, C_PWBT); 69 70 if (pDevice->eOPMode != OP_MODE_ADHOC) { 71 /* set AID */ 72 MACvWriteWord(pDevice, MAC_REG_AIDATIM, wAID); 73 } else { 74 /* set ATIM Window */ 75 /* MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); */ 76 } 77 78 /* Warren:06-18-2004,the sequence must follow PSEN->AUTOSLEEP->GO2DOZE */ 79 /* enable power saving hw function */ 80 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN); 81 82 /* Set AutoSleep */ 83 MACvRegBitsOn(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); 84 85 /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the AUTOSLEEP doesn't work */ 86 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE); 87 88 if (wListenInterval >= 2) { 89 90 /* clear always listen beacon */ 91 MACvRegBitsOff(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 92 93 /* first time set listen next beacon */ 94 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 95 96 pMgmt->wCountToWakeUp = wListenInterval; 97 98 } else { 99 100 /* always listen beacon */ 101 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 102 103 pMgmt->wCountToWakeUp = 0; 104 } 105 106 pDevice->bEnablePSMode = true; 107 108 /* We don't send null pkt in ad hoc mode since beacon will handle this. */ 109 if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) 110 PSbSendNullPacket(pDevice); 111 112 pDevice->bPWBitOn = true; 113 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable...\n"); 114 } 115 116 /* 117 * 118 * Routine Description: 119 * Disable hw power saving functions 120 * 121 * Return Value: 122 * None. 123 * 124 */ 125 126 void PSvDisablePowerSaving(struct vnt_private *pDevice) 127 { 128 129 /* disable power saving hw function */ 130 CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_DISABLE_PS, 0, 131 0, 0, NULL); 132 133 /* clear AutoSleep */ 134 MACvRegBitsOff(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); 135 136 /* set always listen beacon */ 137 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 138 pDevice->bEnablePSMode = false; 139 140 if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) 141 PSbSendNullPacket(pDevice); 142 143 pDevice->bPWBitOn = false; 144 } 145 146 /* 147 * 148 * Routine Description: 149 * Consider to power down when no more packets to tx or rx. 150 * 151 * Return Value: 152 * true, if power down success 153 * false, if fail 154 */ 155 156 int PSbConsiderPowerDown(struct vnt_private *pDevice, int bCheckRxDMA, 157 int bCheckCountToWakeUp) 158 { 159 struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; 160 u8 byData; 161 162 /* check if already in Doze mode */ 163 ControlvReadByte(pDevice, MESSAGE_REQUEST_MACREG, 164 MAC_REG_PSCTL, &byData); 165 166 if ((byData & PSCTL_PS) != 0) 167 return true; 168 169 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 170 /* check if in TIM wake period */ 171 if (pMgmt->bInTIMWake) 172 return false; 173 } 174 175 /* check scan state */ 176 if (pDevice->bCmdRunning) 177 return false; 178 179 /* Tx Burst */ 180 if (pDevice->bPSModeTxBurst) 181 return false; 182 183 /* Froce PSEN on */ 184 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN); 185 186 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 187 if (bCheckCountToWakeUp && (pMgmt->wCountToWakeUp == 0 188 || pMgmt->wCountToWakeUp == 1)) { 189 return false; 190 } 191 } 192 193 pDevice->bPSRxBeacon = true; 194 195 /* no Tx, no Rx isr, now go to Doze */ 196 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE); 197 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n"); 198 return true; 199 } 200 201 /* 202 * 203 * Routine Description: 204 * Send PS-POLL packet 205 * 206 * Return Value: 207 * None. 208 * 209 */ 210 211 void PSvSendPSPOLL(struct vnt_private *pDevice) 212 { 213 struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; 214 struct vnt_tx_mgmt *pTxPacket = NULL; 215 216 memset(pMgmt->pbyPSPacketPool, 0, sizeof(struct vnt_tx_mgmt) 217 + WLAN_HDR_ADDR2_LEN); 218 pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyPSPacketPool; 219 pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket 220 + sizeof(struct vnt_tx_mgmt)); 221 222 pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16( 223 ( 224 WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) | 225 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) | 226 WLAN_SET_FC_PWRMGT(0) 227 )); 228 229 pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15; 230 memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); 231 memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); 232 pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN; 233 pTxPacket->cbPayloadLen = 0; 234 235 /* log failure if sending failed */ 236 if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { 237 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n"); 238 } 239 } 240 241 /* 242 * 243 * Routine Description: 244 * Send NULL packet to AP for notification power state of STA 245 * 246 * Return Value: 247 * None. 248 * 249 */ 250 251 int PSbSendNullPacket(struct vnt_private *pDevice) 252 { 253 struct vnt_tx_mgmt *pTxPacket = NULL; 254 struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; 255 u16 flags = 0; 256 257 if (pDevice->bLinkPass == false) 258 return false; 259 260 if ((pDevice->bEnablePSMode == false) && 261 (pDevice->fTxDataInSleep == false)) { 262 return false; 263 } 264 265 memset(pMgmt->pbyPSPacketPool, 0, sizeof(struct vnt_tx_mgmt) 266 + WLAN_NULLDATA_FR_MAXLEN); 267 pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyPSPacketPool; 268 pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket 269 + sizeof(struct vnt_tx_mgmt)); 270 271 flags = WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) | 272 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL); 273 274 if (pDevice->bEnablePSMode) 275 flags |= WLAN_SET_FC_PWRMGT(1); 276 else 277 flags |= WLAN_SET_FC_PWRMGT(0); 278 279 pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags); 280 281 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) 282 pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((u16)WLAN_SET_FC_TODS(1)); 283 284 memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); 285 memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); 286 memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); 287 pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN; 288 pTxPacket->cbPayloadLen = 0; 289 /* log error if sending failed */ 290 if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { 291 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n"); 292 return false; 293 } 294 return true; 295 } 296 297 /* 298 * 299 * Routine Description: 300 * Check if Next TBTT must wake up 301 * 302 * Return Value: 303 * None. 304 * 305 */ 306 307 int PSbIsNextTBTTWakeUp(struct vnt_private *pDevice) 308 { 309 struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; 310 int bWakeUp = false; 311 312 if (pMgmt->wListenInterval >= 2) { 313 if (pMgmt->wCountToWakeUp == 0) 314 pMgmt->wCountToWakeUp = pMgmt->wListenInterval; 315 316 pMgmt->wCountToWakeUp--; 317 318 if (pMgmt->wCountToWakeUp == 1) { 319 /* Turn on wake up to listen next beacon */ 320 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 321 pDevice->bPSRxBeacon = false; 322 bWakeUp = true; 323 } else if (!pDevice->bPSRxBeacon) { 324 /* Listen until RxBeacon */ 325 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 326 } 327 } 328 return bWakeUp; 329 } 330 331