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 "ttype.h" 41 #include "mac.h" 42 #include "device.h" 43 #include "wmgr.h" 44 #include "power.h" 45 #include "wcmd.h" 46 #include "rxtx.h" 47 #include "card.h" 48 #include "control.h" 49 #include "rndis.h" 50 51 /*--------------------- Static Definitions -------------------------*/ 52 53 /*--------------------- Static Classes ----------------------------*/ 54 55 /*--------------------- Static Variables --------------------------*/ 56 static int msglevel = MSG_LEVEL_INFO; 57 /*--------------------- Static Functions --------------------------*/ 58 59 /*--------------------- Export Variables --------------------------*/ 60 61 /*--------------------- Export Functions --------------------------*/ 62 63 /* 64 * 65 * Routine Description: 66 * Enable hw power saving functions 67 * 68 * Return Value: 69 * None. 70 * 71 */ 72 73 void PSvEnablePowerSaving(void *hDeviceContext, 74 WORD wListenInterval) 75 { 76 PSDevice pDevice = (PSDevice)hDeviceContext; 77 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 78 WORD wAID = pMgmt->wCurrAID | BIT14 | BIT15; 79 80 /* set period of power up before TBTT */ 81 MACvWriteWord(pDevice, MAC_REG_PWBT, C_PWBT); 82 83 if (pDevice->eOPMode != OP_MODE_ADHOC) { 84 /* set AID */ 85 MACvWriteWord(pDevice, MAC_REG_AIDATIM, wAID); 86 } else { 87 /* set ATIM Window */ 88 /* MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); */ 89 } 90 91 /* Warren:06-18-2004,the sequence must follow PSEN->AUTOSLEEP->GO2DOZE */ 92 /* enable power saving hw function */ 93 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN); 94 95 /* Set AutoSleep */ 96 MACvRegBitsOn(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); 97 98 /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the AUTOSLEEP doesn't work */ 99 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE); 100 101 if (wListenInterval >= 2) { 102 103 /* clear always listen beacon */ 104 MACvRegBitsOff(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 105 106 /* first time set listen next beacon */ 107 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 108 109 pMgmt->wCountToWakeUp = wListenInterval; 110 111 } else { 112 113 /* always listen beacon */ 114 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 115 116 pMgmt->wCountToWakeUp = 0; 117 } 118 119 pDevice->bEnablePSMode = TRUE; 120 121 /* We don't send null pkt in ad hoc mode since beacon will handle this. */ 122 if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) 123 PSbSendNullPacket(pDevice); 124 125 pDevice->bPWBitOn = TRUE; 126 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable...\n"); 127 } 128 129 /* 130 * 131 * Routine Description: 132 * Disable hw power saving functions 133 * 134 * Return Value: 135 * None. 136 * 137 */ 138 139 void PSvDisablePowerSaving(void *hDeviceContext) 140 { 141 PSDevice pDevice = (PSDevice)hDeviceContext; 142 /* PSMgmtObject pMgmt = &(pDevice->sMgmtObj); */ 143 144 /* disable power saving hw function */ 145 CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_DISABLE_PS, 0, 146 0, 0, NULL); 147 148 /* clear AutoSleep */ 149 MACvRegBitsOff(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); 150 151 /* set always listen beacon */ 152 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 153 pDevice->bEnablePSMode = FALSE; 154 155 if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) 156 PSbSendNullPacket(pDevice); 157 158 pDevice->bPWBitOn = FALSE; 159 } 160 161 /* 162 * 163 * Routine Description: 164 * Consider to power down when no more packets to tx or rx. 165 * 166 * Return Value: 167 * TRUE, if power down success 168 * FALSE, if fail 169 */ 170 171 BOOL PSbConsiderPowerDown(void *hDeviceContext, 172 BOOL bCheckRxDMA, 173 BOOL bCheckCountToWakeUp) 174 { 175 PSDevice pDevice = (PSDevice)hDeviceContext; 176 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 177 BYTE byData; 178 179 /* check if already in Doze mode */ 180 ControlvReadByte(pDevice, MESSAGE_REQUEST_MACREG, 181 MAC_REG_PSCTL, &byData); 182 183 if ((byData & PSCTL_PS) != 0) 184 return TRUE; 185 186 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 187 /* check if in TIM wake period */ 188 if (pMgmt->bInTIMWake) 189 return FALSE; 190 } 191 192 /* check scan state */ 193 if (pDevice->bCmdRunning) 194 return FALSE; 195 196 /* Tx Burst */ 197 if (pDevice->bPSModeTxBurst) 198 return FALSE; 199 200 /* Froce PSEN on */ 201 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN); 202 203 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 204 if (bCheckCountToWakeUp && (pMgmt->wCountToWakeUp == 0 205 || pMgmt->wCountToWakeUp == 1)) { 206 return FALSE; 207 } 208 } 209 210 pDevice->bPSRxBeacon = TRUE; 211 212 /* no Tx, no Rx isr, now go to Doze */ 213 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE); 214 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n"); 215 return TRUE; 216 } 217 218 /* 219 * 220 * Routine Description: 221 * Send PS-POLL packet 222 * 223 * Return Value: 224 * None. 225 * 226 */ 227 228 void PSvSendPSPOLL(void *hDeviceContext) 229 { 230 PSDevice pDevice = (PSDevice)hDeviceContext; 231 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 232 PSTxMgmtPacket pTxPacket = NULL; 233 234 memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN); 235 pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool; 236 pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); 237 pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16( 238 ( 239 WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) | 240 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) | 241 WLAN_SET_FC_PWRMGT(0) 242 )); 243 244 pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15; 245 memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); 246 memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); 247 pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN; 248 pTxPacket->cbPayloadLen = 0; 249 250 /* log failure if sending failed */ 251 if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { 252 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n"); 253 } 254 } 255 256 /* 257 * 258 * Routine Description: 259 * Send NULL packet to AP for notification power state of STA 260 * 261 * Return Value: 262 * None. 263 * 264 */ 265 266 BOOL PSbSendNullPacket(void *hDeviceContext) 267 { 268 PSDevice pDevice = (PSDevice)hDeviceContext; 269 PSTxMgmtPacket pTxPacket = NULL; 270 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 271 u16 flags = 0; 272 273 if (pDevice->bLinkPass == FALSE) 274 return FALSE; 275 276 if ((pDevice->bEnablePSMode == FALSE) && 277 (pDevice->fTxDataInSleep == FALSE)) { 278 return FALSE; 279 } 280 281 memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN); 282 pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool; 283 pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); 284 285 flags = WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) | 286 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL); 287 288 if (pDevice->bEnablePSMode) 289 flags |= WLAN_SET_FC_PWRMGT(1); 290 else 291 flags |= WLAN_SET_FC_PWRMGT(0); 292 293 pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags); 294 295 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) 296 pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_TODS(1)); 297 298 memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); 299 memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); 300 memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); 301 pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN; 302 pTxPacket->cbPayloadLen = 0; 303 /* log error if sending failed */ 304 if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { 305 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n"); 306 return FALSE; 307 } 308 return TRUE; 309 } 310 311 /* 312 * 313 * Routine Description: 314 * Check if Next TBTT must wake up 315 * 316 * Return Value: 317 * None. 318 * 319 */ 320 321 BOOL PSbIsNextTBTTWakeUp(void *hDeviceContext) 322 { 323 PSDevice pDevice = (PSDevice)hDeviceContext; 324 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 325 BOOL bWakeUp = FALSE; 326 327 if (pMgmt->wListenInterval >= 2) { 328 if (pMgmt->wCountToWakeUp == 0) 329 pMgmt->wCountToWakeUp = pMgmt->wListenInterval; 330 331 pMgmt->wCountToWakeUp--; 332 333 if (pMgmt->wCountToWakeUp == 1) { 334 /* Turn on wake up to listen next beacon */ 335 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 336 pDevice->bPSRxBeacon = FALSE; 337 bWakeUp = TRUE; 338 } else if (!pDevice->bPSRxBeacon) { 339 /* Listen until RxBeacon */ 340 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 341 } 342 } 343 return bWakeUp; 344 } 345 346