Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh...
[pandora-kernel.git] / drivers / staging / vt6655 / 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
49 /*---------------------  Static Definitions -------------------------*/
50
51
52
53
54 /*---------------------  Static Classes  ----------------------------*/
55
56 /*---------------------  Static Variables  --------------------------*/
57 static 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
77 void
78 PSvEnablePowerSaving(
79     void *hDeviceContext,
80     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((void *)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
147 void
148 PSvDisablePowerSaving(
149     void *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
185 BOOL
186 PSbConsiderPowerDown(
187     void *hDeviceContext,
188     BOOL bCheckRxDMA,
189     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
253 void
254 PSvSendPSPOLL(
255     void *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 -*/
299 BOOL
300 PSbSendNullPacket(
301     void *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
385 BOOL
386 PSbIsNextTBTTWakeUp(
387     void *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