Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
power.c
Go to the documentation of this file.
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 */
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 */
94 
95  /* Set AutoSleep */
97 
98  /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the AUTOSLEEP doesn't work */
100 
101  if (wListenInterval >= 2) {
102 
103  /* clear always listen beacon */
105 
106  /* first time set listen next beacon */
108 
109  pMgmt->wCountToWakeUp = wListenInterval;
110 
111  } else {
112 
113  /* always listen beacon */
115 
116  pMgmt->wCountToWakeUp = 0;
117  }
118 
119  pDevice->bEnablePSMode = TRUE;
120 
121  /* We don't send null pkt in ad hoc mode since beacon will handle this. */
122  if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)
123  PSbSendNullPacket(pDevice);
124 
125  pDevice->bPWBitOn = TRUE;
126  DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable...\n");
127 }
128 
129 /*
130  *
131  * Routine Description:
132  * Disable hw power saving functions
133  *
134  * Return Value:
135  * None.
136  *
137  */
138 
139 void PSvDisablePowerSaving(void *hDeviceContext)
140 {
141  PSDevice pDevice = (PSDevice)hDeviceContext;
142  /* PSMgmtObject pMgmt = &(pDevice->sMgmtObj); */
143 
144  /* disable power saving hw function */
146  0, 0, NULL);
147 
148  /* clear AutoSleep */
150 
151  /* set always listen beacon */
153  pDevice->bEnablePSMode = FALSE;
154 
155  if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)
156  PSbSendNullPacket(pDevice);
157 
158  pDevice->bPWBitOn = FALSE;
159 }
160 
161 /*
162  *
163  * Routine Description:
164  * Consider to power down when no more packets to tx or rx.
165  *
166  * Return Value:
167  * TRUE, if power down success
168  * FALSE, if fail
169  */
170 
171 BOOL PSbConsiderPowerDown(void *hDeviceContext,
172  BOOL bCheckRxDMA,
173  BOOL bCheckCountToWakeUp)
174 {
175  PSDevice pDevice = (PSDevice)hDeviceContext;
176  PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
177  BYTE byData;
178 
179  /* check if already in Doze mode */
181  MAC_REG_PSCTL, &byData);
182 
183  if ((byData & PSCTL_PS) != 0)
184  return TRUE;
185 
186  if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
187  /* check if in TIM wake period */
188  if (pMgmt->bInTIMWake)
189  return FALSE;
190  }
191 
192  /* check scan state */
193  if (pDevice->bCmdRunning)
194  return FALSE;
195 
196  /* Tx Burst */
197  if (pDevice->bPSModeTxBurst)
198  return FALSE;
199 
200  /* Froce PSEN on */
202 
203  if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
204  if (bCheckCountToWakeUp && (pMgmt->wCountToWakeUp == 0
205  || pMgmt->wCountToWakeUp == 1)) {
206  return FALSE;
207  }
208  }
209 
210  pDevice->bPSRxBeacon = TRUE;
211 
212  /* no Tx, no Rx isr, now go to Doze */
214  DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
215  return TRUE;
216 }
217 
218 /*
219  *
220  * Routine Description:
221  * Send PS-POLL packet
222  *
223  * Return Value:
224  * None.
225  *
226  */
227 
228 void PSvSendPSPOLL(void *hDeviceContext)
229 {
230  PSDevice pDevice = (PSDevice)hDeviceContext;
231  PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
232  PSTxMgmtPacket pTxPacket = NULL;
233 
235  pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
236  pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
237  pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
238  (
242  ));
243 
244  pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
245  memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
246  memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
247  pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
248  pTxPacket->cbPayloadLen = 0;
249 
250  /* log failure if sending failed */
251  if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
252  DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
253  }
254 }
255 
256 /*
257  *
258  * Routine Description:
259  * Send NULL packet to AP for notification power state of STA
260  *
261  * Return Value:
262  * None.
263  *
264  */
265 
266 BOOL PSbSendNullPacket(void *hDeviceContext)
267 {
268  PSDevice pDevice = (PSDevice)hDeviceContext;
269  PSTxMgmtPacket pTxPacket = NULL;
270  PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
271  u16 flags = 0;
272 
273  if (pDevice->bLinkPass == FALSE)
274  return FALSE;
275 
276  if ((pDevice->bEnablePSMode == FALSE) &&
277  (pDevice->fTxDataInSleep == FALSE)) {
278  return FALSE;
279  }
280 
282  pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
283  pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
284 
287 
288  if (pDevice->bEnablePSMode)
289  flags |= WLAN_SET_FC_PWRMGT(1);
290  else
291  flags |= WLAN_SET_FC_PWRMGT(0);
292 
293  pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags);
294 
295  if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA)
296  pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_TODS(1));
297 
298  memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
299  memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
300  memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
301  pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
302  pTxPacket->cbPayloadLen = 0;
303  /* log error if sending failed */
304  if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
305  DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
306  return FALSE;
307  }
308  return TRUE;
309 }
310 
311 /*
312  *
313  * Routine Description:
314  * Check if Next TBTT must wake up
315  *
316  * Return Value:
317  * None.
318  *
319  */
320 
321 BOOL PSbIsNextTBTTWakeUp(void *hDeviceContext)
322 {
323  PSDevice pDevice = (PSDevice)hDeviceContext;
324  PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
325  BOOL bWakeUp = FALSE;
326 
327  if (pMgmt->wListenInterval >= 2) {
328  if (pMgmt->wCountToWakeUp == 0)
329  pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
330 
331  pMgmt->wCountToWakeUp--;
332 
333  if (pMgmt->wCountToWakeUp == 1) {
334  /* Turn on wake up to listen next beacon */
336  pDevice->bPSRxBeacon = FALSE;
337  bWakeUp = TRUE;
338  } else if (!pDevice->bPSRxBeacon) {
339  /* Listen until RxBeacon */
341  }
342  }
343  return bWakeUp;
344 }
345