power.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. #include "ttype.h"
  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. /*--------------------- Static Definitions -------------------------*/
  48. /*--------------------- Static Classes ----------------------------*/
  49. /*--------------------- Static Variables --------------------------*/
  50. static int msglevel =MSG_LEVEL_INFO;
  51. /*--------------------- Static Functions --------------------------*/
  52. /*--------------------- Export Variables --------------------------*/
  53. /*--------------------- Export Functions --------------------------*/
  54. /*+
  55. *
  56. * Routine Description:
  57. * Enable hw power saving functions
  58. *
  59. * Return Value:
  60. * None.
  61. *
  62. -*/
  63. void
  64. PSvEnablePowerSaving(
  65. void *hDeviceContext,
  66. unsigned short wListenInterval
  67. )
  68. {
  69. PSDevice pDevice = (PSDevice)hDeviceContext;
  70. PSMgmtObject pMgmt = pDevice->pMgmt;
  71. unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
  72. // set period of power up before TBTT
  73. VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
  74. if (pDevice->eOPMode != OP_MODE_ADHOC) {
  75. // set AID
  76. VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
  77. } else {
  78. // set ATIM Window
  79. MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
  80. }
  81. // Set AutoSleep
  82. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
  83. // Set HWUTSF
  84. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
  85. if (wListenInterval >= 2) {
  86. // clear always listen beacon
  87. MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
  88. //pDevice->wCFG &= ~CFG_ALB;
  89. // first time set listen next beacon
  90. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
  91. pMgmt->wCountToWakeUp = wListenInterval;
  92. }
  93. else {
  94. // always listen beacon
  95. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
  96. //pDevice->wCFG |= CFG_ALB;
  97. pMgmt->wCountToWakeUp = 0;
  98. }
  99. // enable power saving hw function
  100. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
  101. pDevice->bEnablePSMode = true;
  102. if (pDevice->eOPMode == OP_MODE_ADHOC) {
  103. // bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
  104. }
  105. // We don't send null pkt in ad hoc mode since beacon will handle this.
  106. else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
  107. PSbSendNullPacket(pDevice);
  108. }
  109. pDevice->bPWBitOn = true;
  110. DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n");
  111. return;
  112. }
  113. /*+
  114. *
  115. * Routine Description:
  116. * Disable hw power saving functions
  117. *
  118. * Return Value:
  119. * None.
  120. *
  121. -*/
  122. void
  123. PSvDisablePowerSaving(
  124. void *hDeviceContext
  125. )
  126. {
  127. PSDevice pDevice = (PSDevice)hDeviceContext;
  128. // PSMgmtObject pMgmt = pDevice->pMgmt;
  129. // disable power saving hw function
  130. MACbPSWakeup(pDevice->PortOffset);
  131. //clear AutoSleep
  132. MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
  133. //clear HWUTSF
  134. MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
  135. // set always listen beacon
  136. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
  137. pDevice->bEnablePSMode = false;
  138. if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
  139. PSbSendNullPacket(pDevice);
  140. }
  141. pDevice->bPWBitOn = false;
  142. return;
  143. }
  144. /*+
  145. *
  146. * Routine Description:
  147. * Consider to power down when no more packets to tx or rx.
  148. *
  149. * Return Value:
  150. * true, if power down success
  151. * false, if fail
  152. -*/
  153. bool
  154. PSbConsiderPowerDown(
  155. void *hDeviceContext,
  156. bool bCheckRxDMA,
  157. bool bCheckCountToWakeUp
  158. )
  159. {
  160. PSDevice pDevice = (PSDevice)hDeviceContext;
  161. PSMgmtObject pMgmt = pDevice->pMgmt;
  162. unsigned int uIdx;
  163. // check if already in Doze mode
  164. if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
  165. return true;
  166. if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
  167. // check if in TIM wake period
  168. if (pMgmt->bInTIMWake)
  169. return false;
  170. }
  171. // check scan state
  172. if (pDevice->bCmdRunning)
  173. return false;
  174. // Froce PSEN on
  175. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
  176. // check if all TD are empty,
  177. for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
  178. if (pDevice->iTDUsed[uIdx] != 0)
  179. return false;
  180. }
  181. // check if rx isr is clear
  182. if (bCheckRxDMA &&
  183. ((pDevice->dwIsr& ISR_RXDMA0) != 0) &&
  184. ((pDevice->dwIsr & ISR_RXDMA1) != 0)){
  185. return false;
  186. }
  187. if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
  188. if (bCheckCountToWakeUp &&
  189. (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) {
  190. return false;
  191. }
  192. }
  193. // no Tx, no Rx isr, now go to Doze
  194. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
  195. DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
  196. return true;
  197. }
  198. /*+
  199. *
  200. * Routine Description:
  201. * Send PS-POLL packet
  202. *
  203. * Return Value:
  204. * None.
  205. *
  206. -*/
  207. void
  208. PSvSendPSPOLL(
  209. void *hDeviceContext
  210. )
  211. {
  212. PSDevice pDevice = (PSDevice)hDeviceContext;
  213. PSMgmtObject pMgmt = pDevice->pMgmt;
  214. PSTxMgmtPacket pTxPacket = NULL;
  215. memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN);
  216. pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
  217. pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
  218. pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
  219. (
  220. WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
  221. WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) |
  222. WLAN_SET_FC_PWRMGT(0)
  223. ));
  224. pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
  225. memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
  226. memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
  227. pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
  228. pTxPacket->cbPayloadLen = 0;
  229. // send the frame
  230. if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
  231. DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
  232. }
  233. else {
  234. // DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet success..\n");
  235. };
  236. return;
  237. }
  238. /*+
  239. *
  240. * Routine Description:
  241. * Send NULL packet to AP for notification power state of STA
  242. *
  243. * Return Value:
  244. * None.
  245. *
  246. -*/
  247. bool
  248. PSbSendNullPacket(
  249. void *hDeviceContext
  250. )
  251. {
  252. PSDevice pDevice = (PSDevice)hDeviceContext;
  253. PSTxMgmtPacket pTxPacket = NULL;
  254. PSMgmtObject pMgmt = pDevice->pMgmt;
  255. unsigned int uIdx;
  256. if (pDevice->bLinkPass == false) {
  257. return false;
  258. }
  259. #ifdef TxInSleep
  260. if ((pDevice->bEnablePSMode == false) &&
  261. (pDevice->fTxDataInSleep == false)){
  262. return false;
  263. }
  264. #else
  265. if (pDevice->bEnablePSMode == false) {
  266. return false;
  267. }
  268. #endif
  269. if (pDevice->bEnablePSMode) {
  270. for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
  271. if (pDevice->iTDUsed[uIdx] != 0)
  272. return false;
  273. }
  274. }
  275. memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
  276. pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
  277. pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
  278. if (pDevice->bEnablePSMode) {
  279. pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
  280. (
  281. WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
  282. WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
  283. WLAN_SET_FC_PWRMGT(1)
  284. ));
  285. }
  286. else {
  287. pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
  288. (
  289. WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
  290. WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
  291. WLAN_SET_FC_PWRMGT(0)
  292. ));
  293. }
  294. if(pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
  295. pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_TODS(1));
  296. }
  297. memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
  298. memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
  299. memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
  300. pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
  301. pTxPacket->cbPayloadLen = 0;
  302. // send the frame
  303. if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
  304. DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
  305. return false;
  306. }
  307. else {
  308. // DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet success....\n");
  309. }
  310. return true ;
  311. }
  312. /*+
  313. *
  314. * Routine Description:
  315. * Check if Next TBTT must wake up
  316. *
  317. * Return Value:
  318. * None.
  319. *
  320. -*/
  321. bool
  322. PSbIsNextTBTTWakeUp(
  323. void *hDeviceContext
  324. )
  325. {
  326. PSDevice pDevice = (PSDevice)hDeviceContext;
  327. PSMgmtObject pMgmt = pDevice->pMgmt;
  328. bool bWakeUp = false;
  329. if (pMgmt->wListenInterval >= 2) {
  330. if (pMgmt->wCountToWakeUp == 0) {
  331. pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
  332. }
  333. pMgmt->wCountToWakeUp --;
  334. if (pMgmt->wCountToWakeUp == 1) {
  335. // Turn on wake up to listen next beacon
  336. MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
  337. bWakeUp = true;
  338. }
  339. }
  340. return bWakeUp;
  341. }