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