power.c 9.0 KB

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