]> Pileus Git - ~andy/linux/blob - drivers/staging/vt6656/power.c
Merge remote-tracking branch 'asoc/topic/compress' into asoc-next
[~andy/linux] / 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  * Routine Description:
243  * Send NULL packet to AP for notification power state of STA
244  *
245  * Return Value:
246  *    None.
247  *
248  */
249
250 int PSbSendNullPacket(struct vnt_private *pDevice)
251 {
252         struct vnt_tx_mgmt *pTxPacket = NULL;
253         struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
254         u16 flags = 0;
255
256         if (pDevice->bLinkPass == false)
257                 return false;
258
259         if (pDevice->bEnablePSMode == false && pDevice->tx_trigger == false)
260                 return false;
261
262         memset(pMgmt->pbyPSPacketPool, 0, sizeof(struct vnt_tx_mgmt)
263                 + WLAN_NULLDATA_FR_MAXLEN);
264         pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyPSPacketPool;
265         pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
266                 + sizeof(struct vnt_tx_mgmt));
267
268         flags = WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
269                         WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL);
270
271         if (pDevice->bEnablePSMode)
272                 flags |= WLAN_SET_FC_PWRMGT(1);
273         else
274                 flags |= WLAN_SET_FC_PWRMGT(0);
275
276         pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags);
277
278         if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA)
279                 pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((u16)WLAN_SET_FC_TODS(1));
280
281         memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
282         memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
283         memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
284         pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
285         pTxPacket->cbPayloadLen = 0;
286         /* log error if sending failed */
287         if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
288                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
289                 return false;
290         }
291         return true;
292 }
293
294 /*
295  *
296  * Routine Description:
297  * Check if Next TBTT must wake up
298  *
299  * Return Value:
300  *    None.
301  *
302  */
303
304 int PSbIsNextTBTTWakeUp(struct vnt_private *pDevice)
305 {
306         struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
307         int bWakeUp = false;
308
309         if (pMgmt->wListenInterval >= 2) {
310                 if (pMgmt->wCountToWakeUp == 0)
311                         pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
312
313                 pMgmt->wCountToWakeUp--;
314
315                 if (pMgmt->wCountToWakeUp == 1) {
316                         /* Turn on wake up to listen next beacon */
317                         MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN);
318                         pDevice->bPSRxBeacon = false;
319                         bWakeUp = true;
320                 } else if (!pDevice->bPSRxBeacon) {
321                         /* Listen until RxBeacon */
322                         MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN);
323                 }
324         }
325         return bWakeUp;
326 }
327