Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / vt6656 / power.c
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     // 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
143 void 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
183 BOOL 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
239 void 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
281 BOOL 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
352 BOOL 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