rtl8188e_cmd.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of version 2 of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  17. *
  18. *
  19. ******************************************************************************/
  20. #define _RTL8188E_CMD_C_
  21. #include <osdep_service.h>
  22. #include <drv_types.h>
  23. #include <recv_osdep.h>
  24. #include <mlme_osdep.h>
  25. #include <rtw_ioctl_set.h>
  26. #include <rtl8188e_hal.h>
  27. #define RTL88E_MAX_H2C_BOX_NUMS 4
  28. #define RTL88E_MAX_CMD_LEN 7
  29. #define RTL88E_MESSAGE_BOX_SIZE 4
  30. #define RTL88E_EX_MESSAGE_BOX_SIZE 4
  31. static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num)
  32. {
  33. u8 read_down = false;
  34. int retry_cnts = 100;
  35. u8 valid;
  36. do {
  37. valid = usb_read8(adapt, REG_HMETFR) & BIT(msgbox_num);
  38. if (0 == valid)
  39. read_down = true;
  40. } while ((!read_down) && (retry_cnts--));
  41. return read_down;
  42. }
  43. /*****************************************
  44. * H2C Msg format :
  45. * 0x1DF - 0x1D0
  46. *| 31 - 8 | 7-5 4 - 0 |
  47. *| h2c_msg |Class_ID CMD_ID |
  48. *
  49. * Extend 0x1FF - 0x1F0
  50. *|31 - 0 |
  51. *|ext_msg|
  52. ******************************************/
  53. static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
  54. {
  55. u8 bcmd_down = false;
  56. s32 retry_cnts = 100;
  57. u8 h2c_box_num;
  58. u32 msgbox_addr;
  59. u32 msgbox_ex_addr;
  60. struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
  61. u8 cmd_idx, ext_cmd_len;
  62. u32 h2c_cmd = 0;
  63. u32 h2c_cmd_ex = 0;
  64. s32 ret = _FAIL;
  65. if (!adapt->bFWReady) {
  66. DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n");
  67. return ret;
  68. }
  69. if (!pCmdBuffer)
  70. goto exit;
  71. if (CmdLen > RTL88E_MAX_CMD_LEN)
  72. goto exit;
  73. if (adapt->bSurpriseRemoved)
  74. goto exit;
  75. /* pay attention to if race condition happened in H2C cmd setting. */
  76. do {
  77. h2c_box_num = haldata->LastHMEBoxNum;
  78. if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) {
  79. DBG_88E(" fw read cmd failed...\n");
  80. goto exit;
  81. }
  82. *(u8 *)(&h2c_cmd) = ElementID;
  83. if (CmdLen <= 3) {
  84. memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
  85. } else {
  86. memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3);
  87. ext_cmd_len = CmdLen-3;
  88. memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, ext_cmd_len);
  89. /* Write Ext command */
  90. msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE);
  91. for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) {
  92. usb_write8(adapt, msgbox_ex_addr+cmd_idx, *((u8 *)(&h2c_cmd_ex)+cmd_idx));
  93. }
  94. }
  95. /* Write command */
  96. msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE);
  97. for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) {
  98. usb_write8(adapt, msgbox_addr+cmd_idx, *((u8 *)(&h2c_cmd)+cmd_idx));
  99. }
  100. bcmd_down = true;
  101. haldata->LastHMEBoxNum = (h2c_box_num+1) % RTL88E_MAX_H2C_BOX_NUMS;
  102. } while ((!bcmd_down) && (retry_cnts--));
  103. ret = _SUCCESS;
  104. exit:
  105. return ret;
  106. }
  107. /* bitmap[0:27] = tx_rate_bitmap */
  108. /* bitmap[28:31]= Rate Adaptive id */
  109. /* arg[0:4] = macid */
  110. /* arg[5] = Short GI */
  111. void rtl8188e_Add_RateATid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
  112. {
  113. struct hal_data_8188e *haldata = GET_HAL_DATA(pAdapter);
  114. u8 macid, init_rate, raid, shortGIrate = false;
  115. macid = arg&0x1f;
  116. raid = (bitmap>>28) & 0x0f;
  117. bitmap &= 0x0fffffff;
  118. if (rssi_level != DM_RATR_STA_INIT)
  119. bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, macid, bitmap, rssi_level);
  120. bitmap |= ((raid<<28)&0xf0000000);
  121. init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f;
  122. shortGIrate = (arg & BIT(5)) ? true : false;
  123. if (shortGIrate)
  124. init_rate |= BIT(6);
  125. raid = (bitmap>>28) & 0x0f;
  126. bitmap &= 0x0fffffff;
  127. DBG_88E("%s=> mac_id:%d, raid:%d, ra_bitmap=0x%x, shortGIrate=0x%02x\n",
  128. __func__, macid, raid, bitmap, shortGIrate);
  129. ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv), macid, raid, bitmap, shortGIrate);
  130. }
  131. void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
  132. {
  133. struct setpwrmode_parm H2CSetPwrMode;
  134. struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv;
  135. u8 RLBM = 0; /* 0:Min, 1:Max, 2:User define */
  136. DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__,
  137. Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable);
  138. switch (Mode) {
  139. case PS_MODE_ACTIVE:
  140. H2CSetPwrMode.Mode = 0;
  141. break;
  142. case PS_MODE_MIN:
  143. H2CSetPwrMode.Mode = 1;
  144. break;
  145. case PS_MODE_MAX:
  146. RLBM = 1;
  147. H2CSetPwrMode.Mode = 1;
  148. break;
  149. case PS_MODE_DTIM:
  150. RLBM = 2;
  151. H2CSetPwrMode.Mode = 1;
  152. break;
  153. case PS_MODE_UAPSD_WMM:
  154. H2CSetPwrMode.Mode = 2;
  155. break;
  156. default:
  157. H2CSetPwrMode.Mode = 0;
  158. break;
  159. }
  160. H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps<<4)&0xf0) | (RLBM & 0x0f));
  161. H2CSetPwrMode.AwakeInterval = 1;
  162. H2CSetPwrMode.bAllQueueUAPSD = adapt->registrypriv.uapsd_enable;
  163. if (Mode > 0)
  164. H2CSetPwrMode.PwrState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
  165. else
  166. H2CSetPwrMode.PwrState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
  167. FillH2CCmd_88E(adapt, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
  168. }
  169. void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt)
  170. {
  171. u8 opmode, macid;
  172. u16 mst_rpt = le16_to_cpu(mstatus_rpt);
  173. opmode = (u8)mst_rpt;
  174. macid = (u8)(mst_rpt >> 8);
  175. DBG_88E("### %s: MStatus=%x MACID=%d\n", __func__, opmode, macid);
  176. FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt);
  177. }
  178. static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
  179. {
  180. struct rtw_ieee80211_hdr *pwlanhdr;
  181. __le16 *fctrl;
  182. u32 rate_len, pktlen;
  183. struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
  184. struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
  185. struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
  186. u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  187. pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
  188. fctrl = &(pwlanhdr->frame_ctl);
  189. *(fctrl) = 0;
  190. memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
  191. memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
  192. memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
  193. SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
  194. SetFrameSubType(pframe, WIFI_BEACON);
  195. pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
  196. pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
  197. /* timestamp will be inserted by hardware */
  198. pframe += 8;
  199. pktlen += 8;
  200. /* beacon interval: 2 bytes */
  201. memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
  202. pframe += 2;
  203. pktlen += 2;
  204. /* capability info: 2 bytes */
  205. memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
  206. pframe += 2;
  207. pktlen += 2;
  208. if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
  209. pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ie);
  210. memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ie), pktlen);
  211. goto _ConstructBeacon;
  212. }
  213. /* below for ad-hoc mode */
  214. /* SSID */
  215. pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen);
  216. /* supported rates... */
  217. rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
  218. pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, min_t(u32, rate_len, 8), cur_network->SupportedRates, &pktlen);
  219. /* DS parameter set */
  220. pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen);
  221. if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
  222. u32 ATIMWindow;
  223. /* IBSS Parameter Set... */
  224. ATIMWindow = 0;
  225. pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen);
  226. }
  227. /* todo: ERP IE */
  228. /* EXTERNDED SUPPORTED RATE */
  229. if (rate_len > 8)
  230. pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
  231. /* todo:HT for adhoc */
  232. _ConstructBeacon:
  233. if ((pktlen + TXDESC_SIZE) > 512) {
  234. DBG_88E("beacon frame too large\n");
  235. return;
  236. }
  237. *pLength = pktlen;
  238. }
  239. static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength)
  240. {
  241. struct rtw_ieee80211_hdr *pwlanhdr;
  242. struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
  243. struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
  244. __le16 *fctrl;
  245. struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
  246. pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
  247. /* Frame control. */
  248. fctrl = &(pwlanhdr->frame_ctl);
  249. *(fctrl) = 0;
  250. SetPwrMgt(fctrl);
  251. SetFrameSubType(pframe, WIFI_PSPOLL);
  252. /* AID. */
  253. SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
  254. /* BSSID. */
  255. memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
  256. /* TA. */
  257. memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
  258. *pLength = 16;
  259. }
  260. static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
  261. u32 *pLength,
  262. u8 *StaAddr,
  263. u8 bQoS,
  264. u8 AC,
  265. u8 bEosp,
  266. u8 bForcePowerSave)
  267. {
  268. struct rtw_ieee80211_hdr *pwlanhdr;
  269. __le16 *fctrl;
  270. u32 pktlen;
  271. struct mlme_priv *pmlmepriv = &adapt->mlmepriv;
  272. struct wlan_network *cur_network = &pmlmepriv->cur_network;
  273. struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
  274. struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
  275. struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
  276. pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
  277. fctrl = &pwlanhdr->frame_ctl;
  278. *(fctrl) = 0;
  279. if (bForcePowerSave)
  280. SetPwrMgt(fctrl);
  281. switch (cur_network->network.InfrastructureMode) {
  282. case Ndis802_11Infrastructure:
  283. SetToDs(fctrl);
  284. memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
  285. memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
  286. memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
  287. break;
  288. case Ndis802_11APMode:
  289. SetFrDs(fctrl);
  290. memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
  291. memcpy(pwlanhdr->addr2, pnetwork->MacAddress, ETH_ALEN);
  292. memcpy(pwlanhdr->addr3, myid(&(adapt->eeprompriv)), ETH_ALEN);
  293. break;
  294. case Ndis802_11IBSS:
  295. default:
  296. memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
  297. memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
  298. memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
  299. break;
  300. }
  301. SetSeqNum(pwlanhdr, 0);
  302. if (bQoS) {
  303. struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr;
  304. SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
  305. pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe;
  306. SetPriority(&pwlanqoshdr->qc, AC);
  307. SetEOSP(&pwlanqoshdr->qc, bEosp);
  308. pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos);
  309. } else {
  310. SetFrameSubType(pframe, WIFI_DATA_NULL);
  311. pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
  312. }
  313. *pLength = pktlen;
  314. }
  315. static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID)
  316. {
  317. struct rtw_ieee80211_hdr *pwlanhdr;
  318. __le16 *fctrl;
  319. u8 *mac, *bssid;
  320. u32 pktlen;
  321. struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
  322. struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
  323. struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
  324. pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
  325. mac = myid(&(adapt->eeprompriv));
  326. bssid = cur_network->MacAddress;
  327. fctrl = &(pwlanhdr->frame_ctl);
  328. *(fctrl) = 0;
  329. memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
  330. memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
  331. memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
  332. SetSeqNum(pwlanhdr, 0);
  333. SetFrameSubType(fctrl, WIFI_PROBERSP);
  334. pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
  335. pframe += pktlen;
  336. if (cur_network->IELength > MAX_IE_SZ)
  337. return;
  338. memcpy(pframe, cur_network->IEs, cur_network->IELength);
  339. pframe += cur_network->IELength;
  340. pktlen += cur_network->IELength;
  341. *pLength = pktlen;
  342. }
  343. /* */
  344. /* Description: Fill the reserved packets that FW will use to RSVD page. */
  345. /* Now we just send 4 types packet to rsvd page. */
  346. /* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
  347. /* Input: */
  348. /* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
  349. /* so we need to set the packet length to total length. */
  350. /* true: At the second time, we should send the first packet (default:beacon) */
  351. /* to Hw again and set the length in descriptor to the real beacon length. */
  352. /* 2009.10.15 by tynli. */
  353. static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
  354. {
  355. struct hal_data_8188e *haldata;
  356. struct xmit_frame *pmgntframe;
  357. struct pkt_attrib *pattrib;
  358. struct xmit_priv *pxmitpriv;
  359. struct mlme_ext_priv *pmlmeext;
  360. struct mlme_ext_info *pmlmeinfo;
  361. u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
  362. u32 NullDataLength, QosNullLength;
  363. u8 *ReservedPagePacket;
  364. u8 PageNum, PageNeed, TxDescLen;
  365. u16 BufIndex;
  366. u32 TotalPacketLen;
  367. struct rsvdpage_loc RsvdPageLoc;
  368. struct wlan_bssid_ex *pnetwork;
  369. DBG_88E("%s\n", __func__);
  370. ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
  371. if (!ReservedPagePacket) {
  372. DBG_88E("%s: alloc ReservedPagePacket fail!\n", __func__);
  373. return;
  374. }
  375. haldata = GET_HAL_DATA(adapt);
  376. pxmitpriv = &adapt->xmitpriv;
  377. pmlmeext = &adapt->mlmeextpriv;
  378. pmlmeinfo = &pmlmeext->mlmext_info;
  379. pnetwork = &(pmlmeinfo->network);
  380. TxDescLen = TXDESC_SIZE;
  381. PageNum = 0;
  382. /* 3 (1) beacon * 2 pages */
  383. BufIndex = TXDESC_OFFSET;
  384. ConstructBeacon(adapt, &ReservedPagePacket[BufIndex], &BeaconLength);
  385. /* When we count the first page size, we need to reserve description size for the RSVD */
  386. /* packet, it will be filled in front of the packet in TXPKTBUF. */
  387. PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
  388. /* To reserved 2 pages for beacon buffer. 2010.06.24. */
  389. if (PageNeed == 1)
  390. PageNeed += 1;
  391. PageNum += PageNeed;
  392. haldata->FwRsvdPageStartOffset = PageNum;
  393. BufIndex += PageNeed*128;
  394. /* 3 (2) ps-poll *1 page */
  395. RsvdPageLoc.LocPsPoll = PageNum;
  396. ConstructPSPoll(adapt, &ReservedPagePacket[BufIndex], &PSPollLength);
  397. rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
  398. PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
  399. PageNum += PageNeed;
  400. BufIndex += PageNeed*128;
  401. /* 3 (3) null data * 1 page */
  402. RsvdPageLoc.LocNullData = PageNum;
  403. ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, pnetwork->MacAddress, false, 0, 0, false);
  404. rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
  405. PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
  406. PageNum += PageNeed;
  407. BufIndex += PageNeed*128;
  408. /* 3 (4) probe response * 1page */
  409. RsvdPageLoc.LocProbeRsp = PageNum;
  410. ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, pnetwork->MacAddress, false);
  411. rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
  412. PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
  413. PageNum += PageNeed;
  414. BufIndex += PageNeed*128;
  415. /* 3 (5) Qos null data */
  416. RsvdPageLoc.LocQosNull = PageNum;
  417. ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex],
  418. &QosNullLength, pnetwork->MacAddress, true, 0, 0, false);
  419. rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
  420. PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
  421. PageNum += PageNeed;
  422. TotalPacketLen = BufIndex + QosNullLength;
  423. pmgntframe = alloc_mgtxmitframe(pxmitpriv);
  424. if (!pmgntframe)
  425. goto exit;
  426. /* update attribute */
  427. pattrib = &pmgntframe->attrib;
  428. update_mgntframe_attrib(adapt, pattrib);
  429. pattrib->qsel = 0x10;
  430. pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
  431. pattrib->pktlen = pattrib->last_txcmdsz;
  432. memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
  433. rtw_hal_mgnt_xmit(adapt, pmgntframe);
  434. DBG_88E("%s: Set RSVD page location to Fw\n", __func__);
  435. FillH2CCmd_88E(adapt, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
  436. exit:
  437. kfree(ReservedPagePacket);
  438. }
  439. void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
  440. {
  441. struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
  442. struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
  443. struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
  444. bool bSendBeacon = false;
  445. bool bcn_valid = false;
  446. u8 DLBcnCount = 0;
  447. u32 poll = 0;
  448. DBG_88E("%s mstatus(%x)\n", __func__, mstatus);
  449. if (mstatus == 1) {
  450. /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
  451. /* Suggested by filen. Added by tynli. */
  452. usb_write16(adapt, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
  453. /* Do not set TSF again here or vWiFi beacon DMA INT will not work. */
  454. /* Set REG_CR bit 8. DMA beacon by SW. */
  455. haldata->RegCR_1 |= BIT(0);
  456. usb_write8(adapt, REG_CR+1, haldata->RegCR_1);
  457. /* Disable Hw protection for a time which revserd for Hw sending beacon. */
  458. /* Fix download reserved page packet fail that access collision with the protection time. */
  459. /* 2010.05.11. Added by tynli. */
  460. usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL)&(~BIT(3)));
  461. usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) | BIT(4));
  462. if (haldata->RegFwHwTxQCtrl & BIT(6)) {
  463. DBG_88E("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n");
  464. bSendBeacon = true;
  465. }
  466. /* Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */
  467. usb_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl&(~BIT(6))));
  468. haldata->RegFwHwTxQCtrl &= (~BIT(6));
  469. /* Clear beacon valid check bit. */
  470. rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
  471. DLBcnCount = 0;
  472. poll = 0;
  473. do {
  474. /* download rsvd page. */
  475. SetFwRsvdPagePkt(adapt, false);
  476. DLBcnCount++;
  477. do {
  478. yield();
  479. /* mdelay(10); */
  480. /* check rsvd page download OK. */
  481. rtw_hal_get_hwreg(adapt, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid));
  482. poll++;
  483. } while (!bcn_valid && (poll%10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
  484. } while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
  485. if (adapt->bSurpriseRemoved || adapt->bDriverStopped)
  486. ;
  487. else if (!bcn_valid)
  488. DBG_88E("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
  489. else
  490. DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
  491. /* */
  492. /* We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */
  493. /* because we need to free the Tx BCN Desc which is used by the first reserved page packet. */
  494. /* At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return */
  495. /* the beacon TCB in the following code. 2011.11.23. by tynli. */
  496. /* */
  497. /* Enable Bcn */
  498. usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) | BIT(3));
  499. usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL)&(~BIT(4)));
  500. /* To make sure that if there exists an adapter which would like to send beacon. */
  501. /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */
  502. /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
  503. /* the beacon cannot be sent by HW. */
  504. /* 2010.06.23. Added by tynli. */
  505. if (bSendBeacon) {
  506. usb_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl | BIT(6)));
  507. haldata->RegFwHwTxQCtrl |= BIT(6);
  508. }
  509. /* Update RSVD page location H2C to Fw. */
  510. if (bcn_valid) {
  511. rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
  512. DBG_88E("Set RSVD page location to Fw.\n");
  513. }
  514. /* Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */
  515. /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
  516. haldata->RegCR_1 &= (~BIT(0));
  517. usb_write8(adapt, REG_CR+1, haldata->RegCR_1);
  518. }
  519. }