linux/drivers/staging/vt6655/power.c
<<
>>
Prefs
   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
  49/*---------------------  Static Definitions -------------------------*/
  50
  51/*---------------------  Static Classes  ----------------------------*/
  52
  53/*---------------------  Static Variables  --------------------------*/
  54static int msglevel = MSG_LEVEL_INFO;
  55/*---------------------  Static Functions  --------------------------*/
  56
  57/*---------------------  Export Variables  --------------------------*/
  58
  59/*---------------------  Export Functions  --------------------------*/
  60
  61/*+
  62 *
  63 * Routine Description:
  64 * Enable hw power saving functions
  65 *
  66 * Return Value:
  67 *    None.
  68 *
  69 -*/
  70
  71void
  72PSvEnablePowerSaving(
  73        void *hDeviceContext,
  74        unsigned short wListenInterval
  75)
  76{
  77        PSDevice        pDevice = (PSDevice)hDeviceContext;
  78        PSMgmtObject    pMgmt = pDevice->pMgmt;
  79        unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
  80
  81        // set period of power up before TBTT
  82        VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
  83        if (pDevice->eOPMode != OP_MODE_ADHOC) {
  84                // set AID
  85                VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
  86        } else {
  87                // set ATIM Window
  88                MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
  89        }
  90        // Set AutoSleep
  91        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
  92        // Set HWUTSF
  93        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
  94
  95        if (wListenInterval >= 2) {
  96                // clear always listen beacon
  97                MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
  98                //pDevice->wCFG &= ~CFG_ALB;
  99                // first time set listen next beacon
 100                MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
 101                pMgmt->wCountToWakeUp = wListenInterval;
 102        } else {
 103                // always listen beacon
 104                MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
 105                //pDevice->wCFG |= CFG_ALB;
 106                pMgmt->wCountToWakeUp = 0;
 107        }
 108
 109        // enable power saving hw function
 110        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
 111        pDevice->bEnablePSMode = true;
 112
 113        if (pDevice->eOPMode == OP_MODE_ADHOC) {
 114//        bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
 115        }
 116        // We don't send null pkt in ad hoc mode since beacon will handle this.
 117        else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
 118                PSbSendNullPacket(pDevice);
 119        }
 120        pDevice->bPWBitOn = true;
 121        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n");
 122        return;
 123}
 124
 125/*+
 126 *
 127 * Routine Description:
 128 * Disable hw power saving functions
 129 *
 130 * Return Value:
 131 *    None.
 132 *
 133 -*/
 134
 135void
 136PSvDisablePowerSaving(
 137        void *hDeviceContext
 138)
 139{
 140        PSDevice        pDevice = (PSDevice)hDeviceContext;
 141//    PSMgmtObject    pMgmt = pDevice->pMgmt;
 142
 143        // disable power saving hw function
 144        MACbPSWakeup(pDevice->PortOffset);
 145        //clear AutoSleep
 146        MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
 147        //clear HWUTSF
 148        MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
 149        // set always listen beacon
 150        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
 151
 152        pDevice->bEnablePSMode = false;
 153
 154        if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
 155                PSbSendNullPacket(pDevice);
 156        }
 157        pDevice->bPWBitOn = false;
 158        return;
 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
 171bool
 172PSbConsiderPowerDown(
 173        void *hDeviceContext,
 174        bool bCheckRxDMA,
 175        bool bCheckCountToWakeUp
 176)
 177{
 178        PSDevice        pDevice = (PSDevice)hDeviceContext;
 179        PSMgmtObject    pMgmt = pDevice->pMgmt;
 180        unsigned int uIdx;
 181
 182        // check if already in Doze mode
 183        if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
 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        // Force PSEN on
 197        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
 198
 199        // check if all TD are empty,
 200        for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
 201                if (pDevice->iTDUsed[uIdx] != 0)
 202                        return false;
 203        }
 204
 205        // check if rx isr is clear
 206        if (bCheckRxDMA &&
 207            ((pDevice->dwIsr & ISR_RXDMA0) != 0) &&
 208            ((pDevice->dwIsr & ISR_RXDMA1) != 0)) {
 209                return false;
 210        }
 211
 212        if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
 213                if (bCheckCountToWakeUp &&
 214                    (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) {
 215                        return false;
 216                }
 217        }
 218
 219        // no Tx, no Rx isr, now go to Doze
 220        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
 221        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
 222        return true;
 223}
 224
 225/*+
 226 *
 227 * Routine Description:
 228 * Send PS-POLL packet
 229 *
 230 * Return Value:
 231 *    None.
 232 *
 233 -*/
 234
 235void
 236PSvSendPSPOLL(
 237        void *hDeviceContext
 238)
 239{
 240        PSDevice            pDevice = (PSDevice)hDeviceContext;
 241        PSMgmtObject        pMgmt = pDevice->pMgmt;
 242        PSTxMgmtPacket      pTxPacket = NULL;
 243
 244        memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN);
 245        pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
 246        pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
 247        pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
 248                (
 249                        WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
 250                        WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) |
 251                        WLAN_SET_FC_PWRMGT(0)
 252));
 253        pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
 254        memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
 255        memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
 256        pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
 257        pTxPacket->cbPayloadLen = 0;
 258        // send the frame
 259        if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
 260                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
 261        } else {
 262//        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet success..\n");
 263        };
 264
 265        return;
 266}
 267
 268/*+
 269 *
 270 * Routine Description:
 271 * Send NULL packet to AP for notification power state of STA
 272 *
 273 * Return Value:
 274 *    None.
 275 *
 276 -*/
 277bool
 278PSbSendNullPacket(
 279        void *hDeviceContext
 280)
 281{
 282        PSDevice            pDevice = (PSDevice)hDeviceContext;
 283        PSTxMgmtPacket      pTxPacket = NULL;
 284        PSMgmtObject        pMgmt = pDevice->pMgmt;
 285        unsigned int uIdx;
 286
 287        if (pDevice->bLinkPass == false) {
 288                return false;
 289        }
 290#ifdef TxInSleep
 291        if ((pDevice->bEnablePSMode == false) &&
 292            (pDevice->fTxDataInSleep == false)) {
 293                return false;
 294        }
 295#else
 296        if (pDevice->bEnablePSMode == false) {
 297                return false;
 298        }
 299#endif
 300        if (pDevice->bEnablePSMode) {
 301                for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
 302                        if (pDevice->iTDUsed[uIdx] != 0)
 303                                return false;
 304                }
 305        }
 306
 307        memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
 308        pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
 309        pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
 310
 311        if (pDevice->bEnablePSMode) {
 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(1)
 317));
 318        } else {
 319                pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
 320                        (
 321                                WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
 322                                WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
 323                                WLAN_SET_FC_PWRMGT(0)
 324));
 325        }
 326
 327        if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
 328                pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_TODS(1));
 329        }
 330
 331        memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
 332        memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
 333        memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
 334        pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
 335        pTxPacket->cbPayloadLen = 0;
 336        // send the frame
 337        if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
 338                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
 339                return false;
 340        } else {
 341//            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet success....\n");
 342        }
 343
 344        return true;
 345}
 346
 347/*+
 348 *
 349 * Routine Description:
 350 * Check if Next TBTT must wake up
 351 *
 352 * Return Value:
 353 *    None.
 354 *
 355 -*/
 356
 357bool
 358PSbIsNextTBTTWakeUp(
 359        void *hDeviceContext
 360)
 361{
 362        PSDevice         pDevice = (PSDevice)hDeviceContext;
 363        PSMgmtObject        pMgmt = pDevice->pMgmt;
 364        bool bWakeUp = false;
 365
 366        if (pMgmt->wListenInterval >= 2) {
 367                if (pMgmt->wCountToWakeUp == 0) {
 368                        pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
 369                }
 370
 371                pMgmt->wCountToWakeUp--;
 372
 373                if (pMgmt->wCountToWakeUp == 1) {
 374                        // Turn on wake up to listen next beacon
 375                        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
 376                        bWakeUp = true;
 377                }
 378
 379        }
 380
 381        return bWakeUp;
 382}
 383