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