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