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