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 --------------------------*/ 56static 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 73void 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 // Set AutoSleep 95 MACvRegBitsOn(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); 96 97 //Warren:MUST turn on this once before turn on AUTOSLEEP ,or the AUTOSLEEP doesn't work 98 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE); 99 100 101 if (wListenInterval >= 2) { 102 103 // clear always listen beacon 104 MACvRegBitsOff(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 105 // first time set listen next beacon 106 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 107 108 pMgmt->wCountToWakeUp = wListenInterval; 109 110 } 111 else { 112 113 // always listen beacon 114 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 115 pMgmt->wCountToWakeUp = 0; 116 117 } 118 119 pDevice->bEnablePSMode = TRUE; 120 121 if (pDevice->eOPMode == OP_MODE_ADHOC) { 122 /* bMgrPrepareBeaconToSend((void *) pDevice, pMgmt); */ 123 } 124 // We don't send null pkt in ad hoc mode since beacon will handle this. 125 else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) { 126 PSbSendNullPacket(pDevice); 127 } 128 pDevice->bPWBitOn = TRUE; 129 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n"); 130 return; 131} 132 133/*+ 134 * 135 * Routine Description: 136 * Disable hw power saving functions 137 * 138 * Return Value: 139 * None. 140 * 141-*/ 142 143void PSvDisablePowerSaving(void *hDeviceContext) 144{ 145 PSDevice pDevice = (PSDevice)hDeviceContext; 146// PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 147 148 149 // disable power saving hw function 150 CONTROLnsRequestOut(pDevice, 151 MESSAGE_TYPE_DISABLE_PS, 152 0, 153 0, 154 0, 155 NULL 156 ); 157 158 //clear AutoSleep 159 MACvRegBitsOff(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); 160 161 // set always listen beacon 162 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN); 163 164 pDevice->bEnablePSMode = FALSE; 165 166 if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) { 167 PSbSendNullPacket(pDevice); 168 } 169 pDevice->bPWBitOn = FALSE; 170 return; 171} 172 173/*+ 174 * 175 * Routine Description: 176 * Consider to power down when no more packets to tx or rx. 177 * 178 * Return Value: 179 * TRUE, if power down success 180 * FALSE, if fail 181-*/ 182 183BOOL PSbConsiderPowerDown(void *hDeviceContext, 184 BOOL bCheckRxDMA, 185 BOOL bCheckCountToWakeUp) 186{ 187 PSDevice pDevice = (PSDevice)hDeviceContext; 188 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 189 BYTE byData; 190 191 192 // check if already in Doze mode 193 ControlvReadByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PSCTL, &byData); 194 if ( (byData & PSCTL_PS) != 0 ) 195 return TRUE;; 196 197 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 198 // check if in TIM wake period 199 if (pMgmt->bInTIMWake) 200 return FALSE; 201 } 202 203 // check scan state 204 if (pDevice->bCmdRunning) 205 return FALSE; 206 207 //Tx Burst 208 if ( pDevice->bPSModeTxBurst ) 209 return FALSE; 210 211 // Froce PSEN on 212 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN); 213 214 if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 215 if (bCheckCountToWakeUp && 216 (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) { 217 return FALSE; 218 } 219 } 220 221 pDevice->bPSRxBeacon = TRUE; 222 // no Tx, no Rx isr, now go to Doze 223 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE); 224 225 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n"); 226 return TRUE; 227} 228 229/*+ 230 * 231 * Routine Description: 232 * Send PS-POLL packet 233 * 234 * Return Value: 235 * None. 236 * 237-*/ 238 239void PSvSendPSPOLL(void *hDeviceContext) 240{ 241 PSDevice pDevice = (PSDevice)hDeviceContext; 242 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 243 PSTxMgmtPacket pTxPacket = NULL; 244 245 246 memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN); 247 pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool; 248 pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); 249 pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16( 250 ( 251 WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) | 252 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) | 253 WLAN_SET_FC_PWRMGT(0) 254 )); 255 pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15; 256 memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); 257 memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); 258 pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN; 259 pTxPacket->cbPayloadLen = 0; 260 // send the frame 261 if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { 262 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n"); 263 } 264 else { 265// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet success..\n"); 266 }; 267 268 return; 269} 270 271/*+ 272 * 273 * Routine Description: 274 * Send NULL packet to AP for notification power state of STA 275 * 276 * Return Value: 277 * None. 278 * 279-*/ 280 281BOOL PSbSendNullPacket(void *hDeviceContext) 282{ 283 PSDevice pDevice = (PSDevice)hDeviceContext; 284 PSTxMgmtPacket pTxPacket = NULL; 285 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 286 287 288 289 if (pDevice->bLinkPass == FALSE) { 290 return FALSE; 291 } 292 293 if ((pDevice->bEnablePSMode == FALSE) && 294 (pDevice->fTxDataInSleep == FALSE)){ 295 return FALSE; 296 } 297 298 memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN); 299 pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool; 300 pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); 301 302 if (pDevice->bEnablePSMode) { 303 304 pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16( 305 ( 306 WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) | 307 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) | 308 WLAN_SET_FC_PWRMGT(1) 309 )); 310 } 311 else { 312 pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16( 313 ( 314 WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) | 315 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) | 316 WLAN_SET_FC_PWRMGT(0) 317 )); 318 } 319 320 if(pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { 321 pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_TODS(1)); 322 } 323 324 memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); 325 memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); 326 memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); 327 pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN; 328 pTxPacket->cbPayloadLen = 0; 329 // send the frame 330 if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { 331 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n"); 332 return FALSE; 333 } 334 else { 335// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet success....\n"); 336 } 337 338 339 return TRUE ; 340} 341 342/*+ 343 * 344 * Routine Description: 345 * Check if Next TBTT must wake up 346 * 347 * Return Value: 348 * None. 349 * 350-*/ 351 352BOOL PSbIsNextTBTTWakeUp(void *hDeviceContext) 353{ 354 355 PSDevice pDevice = (PSDevice)hDeviceContext; 356 PSMgmtObject pMgmt = &(pDevice->sMgmtObj); 357 BOOL bWakeUp = FALSE; 358 359 if (pMgmt->wListenInterval >= 2) { 360 if (pMgmt->wCountToWakeUp == 0) { 361 pMgmt->wCountToWakeUp = pMgmt->wListenInterval; 362 } 363 364 pMgmt->wCountToWakeUp --; 365 366 if (pMgmt->wCountToWakeUp == 1) { 367 368 // Turn on wake up to listen next beacon 369 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 370 pDevice->bPSRxBeacon = FALSE; 371 bWakeUp = TRUE; 372 373 } else if ( !pDevice->bPSRxBeacon ) { 374 //Listen until RxBeacon 375 MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN); 376 } 377 378 } 379 380 return bWakeUp; 381} 382