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 
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
79  void *hDeviceContext,
80  unsigned short wListenInterval
81  )
82 {
83  PSDevice pDevice = (PSDevice)hDeviceContext;
84  PSMgmtObject pMgmt = pDevice->pMgmt;
85  unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
86 
87  // set period of power up before TBTT
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
98  // Set HWUTSF
100 
101  if (wListenInterval >= 2) {
102  // clear always listen beacon
104  //pDevice->wCFG &= ~CFG_ALB;
105  // first time set listen next beacon
107  pMgmt->wCountToWakeUp = wListenInterval;
108  }
109  else {
110  // always listen beacon
112  //pDevice->wCFG |= CFG_ALB;
113  pMgmt->wCountToWakeUp = 0;
114  }
115 
116  // enable power saving hw function
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
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
159  //clear HWUTSF
161  // set always listen beacon
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
187  void *hDeviceContext,
188  bool bCheckRxDMA,
189  bool bCheckCountToWakeUp
190  )
191 {
192  PSDevice pDevice = (PSDevice)hDeviceContext;
193  PSMgmtObject pMgmt = pDevice->pMgmt;
194  unsigned int uIdx;
195 
196  // check if already in Doze mode
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  // Force PSEN on
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
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
255  void *hDeviceContext
256  )
257 {
258  PSDevice pDevice = (PSDevice)hDeviceContext;
259  PSMgmtObject pMgmt = pDevice->pMgmt;
260  PSTxMgmtPacket pTxPacket = NULL;
261 
262 
264  pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
265  pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
266  pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
267  (
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
301  void *hDeviceContext
302  )
303 {
304  PSDevice pDevice = (PSDevice)hDeviceContext;
305  PSTxMgmtPacket pTxPacket = NULL;
306  PSMgmtObject pMgmt = pDevice->pMgmt;
307  unsigned int 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 
331  pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
332  pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
333 
334  if (pDevice->bEnablePSMode) {
335 
336  pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
337  (
341  ));
342  }
343  else {
344  pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
345  (
349  ));
350  }
351 
352  if(pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
353  pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)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
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
405  bWakeUp = true;
406  }
407 
408  }
409 
410  return bWakeUp;
411 }
412