rtl_btc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2009-2013 Realtek Corporation.
  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. * The full GNU General Public License is included in this distribution in the
  15. * file called LICENSE.
  16. *
  17. * Contact Information:
  18. * wlanfae <wlanfae@realtek.com>
  19. * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  20. * Hsinchu 300, Taiwan.
  21. *
  22. * Larry Finger <Larry.Finger@lwfinger.net>
  23. *
  24. *****************************************************************************/
  25. #include "../wifi.h"
  26. #include <linux/vmalloc.h>
  27. #include <linux/module.h>
  28. #include "rtl_btc.h"
  29. #include "halbt_precomp.h"
  30. static struct rtl_btc_ops rtl_btc_operation = {
  31. .btc_init_variables = rtl_btc_init_variables,
  32. .btc_init_variables_wifi_only = rtl_btc_init_variables_wifi_only,
  33. .btc_deinit_variables = rtl_btc_deinit_variables,
  34. .btc_init_hal_vars = rtl_btc_init_hal_vars,
  35. .btc_power_on_setting = rtl_btc_power_on_setting,
  36. .btc_init_hw_config = rtl_btc_init_hw_config,
  37. .btc_init_hw_config_wifi_only = rtl_btc_init_hw_config_wifi_only,
  38. .btc_ips_notify = rtl_btc_ips_notify,
  39. .btc_lps_notify = rtl_btc_lps_notify,
  40. .btc_scan_notify = rtl_btc_scan_notify,
  41. .btc_scan_notify_wifi_only = rtl_btc_scan_notify_wifi_only,
  42. .btc_connect_notify = rtl_btc_connect_notify,
  43. .btc_mediastatus_notify = rtl_btc_mediastatus_notify,
  44. .btc_periodical = rtl_btc_periodical,
  45. .btc_halt_notify = rtl_btc_halt_notify,
  46. .btc_btinfo_notify = rtl_btc_btinfo_notify,
  47. .btc_btmpinfo_notify = rtl_btc_btmpinfo_notify,
  48. .btc_is_limited_dig = rtl_btc_is_limited_dig,
  49. .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
  50. .btc_is_bt_disabled = rtl_btc_is_bt_disabled,
  51. .btc_special_packet_notify = rtl_btc_special_packet_notify,
  52. .btc_switch_band_notify = rtl_btc_switch_band_notify,
  53. .btc_switch_band_notify_wifi_only = rtl_btc_switch_band_notify_wifionly,
  54. .btc_record_pwr_mode = rtl_btc_record_pwr_mode,
  55. .btc_get_lps_val = rtl_btc_get_lps_val,
  56. .btc_get_rpwm_val = rtl_btc_get_rpwm_val,
  57. .btc_is_bt_ctrl_lps = rtl_btc_is_bt_ctrl_lps,
  58. .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on,
  59. .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg,
  60. .btc_display_bt_coex_info = rtl_btc_display_bt_coex_info,
  61. };
  62. void rtl_btc_display_bt_coex_info(struct rtl_priv *rtlpriv, struct seq_file *m)
  63. {
  64. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  65. if (!btcoexist) {
  66. seq_puts(m, "btc_coexist context is NULL!\n");
  67. return;
  68. }
  69. exhalbtc_display_bt_coex_info(btcoexist, m);
  70. }
  71. void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len)
  72. {
  73. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  74. u8 safe_len;
  75. if (!btcoexist)
  76. return;
  77. safe_len = sizeof(btcoexist->pwr_mode_val);
  78. if (safe_len > len)
  79. safe_len = len;
  80. memcpy(btcoexist->pwr_mode_val, buf, safe_len);
  81. }
  82. u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv)
  83. {
  84. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  85. if (!btcoexist)
  86. return 0;
  87. return btcoexist->bt_info.lps_val;
  88. }
  89. u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv)
  90. {
  91. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  92. if (!btcoexist)
  93. return 0;
  94. return btcoexist->bt_info.rpwm_val;
  95. }
  96. bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv)
  97. {
  98. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  99. if (!btcoexist)
  100. return false;
  101. return btcoexist->bt_info.bt_ctrl_lps;
  102. }
  103. bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv)
  104. {
  105. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  106. if (!btcoexist)
  107. return false;
  108. return btcoexist->bt_info.bt_lps_on;
  109. }
  110. void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg,
  111. u8 *ctrl_agg_size, u8 *agg_size)
  112. {
  113. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  114. if (!btcoexist) {
  115. *reject_agg = false;
  116. *ctrl_agg_size = false;
  117. return;
  118. }
  119. if (reject_agg)
  120. *reject_agg = btcoexist->bt_info.reject_agg_pkt;
  121. if (ctrl_agg_size)
  122. *ctrl_agg_size = btcoexist->bt_info.bt_ctrl_agg_buf_size;
  123. if (agg_size)
  124. *agg_size = btcoexist->bt_info.agg_buf_size;
  125. }
  126. static void rtl_btc_alloc_variable(struct rtl_priv *rtlpriv, bool wifi_only)
  127. {
  128. if (wifi_only)
  129. rtlpriv->btcoexist.wifi_only_context =
  130. kzalloc(sizeof(struct wifi_only_cfg), GFP_KERNEL);
  131. else
  132. rtlpriv->btcoexist.btc_context =
  133. kzalloc(sizeof(struct btc_coexist), GFP_KERNEL);
  134. }
  135. static void rtl_btc_free_variable(struct rtl_priv *rtlpriv)
  136. {
  137. kfree(rtlpriv->btcoexist.btc_context);
  138. rtlpriv->btcoexist.btc_context = NULL;
  139. kfree(rtlpriv->btcoexist.wifi_only_context);
  140. rtlpriv->btcoexist.wifi_only_context = NULL;
  141. }
  142. void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
  143. {
  144. rtl_btc_alloc_variable(rtlpriv, false);
  145. exhalbtc_initlize_variables(rtlpriv);
  146. exhalbtc_bind_bt_coex_withadapter(rtlpriv);
  147. }
  148. void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv)
  149. {
  150. rtl_btc_alloc_variable(rtlpriv, true);
  151. exhalbtc_initlize_variables_wifi_only(rtlpriv);
  152. }
  153. void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv)
  154. {
  155. rtl_btc_free_variable(rtlpriv);
  156. }
  157. void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv)
  158. {
  159. /* move ant_num, bt_type and single_ant_path to
  160. * exhalbtc_bind_bt_coex_withadapter()
  161. */
  162. }
  163. void rtl_btc_power_on_setting(struct rtl_priv *rtlpriv)
  164. {
  165. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  166. if (!btcoexist)
  167. return;
  168. exhalbtc_power_on_setting(btcoexist);
  169. }
  170. void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
  171. {
  172. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  173. u8 bt_exist;
  174. bt_exist = rtl_get_hwpg_bt_exist(rtlpriv);
  175. RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
  176. "%s, bt_exist is %d\n", __func__, bt_exist);
  177. if (!btcoexist)
  178. return;
  179. exhalbtc_init_hw_config(btcoexist, !bt_exist);
  180. exhalbtc_init_coex_dm(btcoexist);
  181. }
  182. void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv)
  183. {
  184. struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
  185. if (!wifionly_cfg)
  186. return;
  187. exhalbtc_init_hw_config_wifi_only(wifionly_cfg);
  188. }
  189. void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
  190. {
  191. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  192. if (!btcoexist)
  193. return;
  194. exhalbtc_ips_notify(btcoexist, type);
  195. if (type == ERFON) {
  196. /* In some situation, it doesn't scan after leaving IPS, and
  197. * this will cause btcoex in wrong state.
  198. */
  199. exhalbtc_scan_notify(btcoexist, 1);
  200. exhalbtc_scan_notify(btcoexist, 0);
  201. }
  202. }
  203. void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
  204. {
  205. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  206. if (!btcoexist)
  207. return;
  208. exhalbtc_lps_notify(btcoexist, type);
  209. }
  210. void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
  211. {
  212. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  213. if (!btcoexist)
  214. return;
  215. exhalbtc_scan_notify(btcoexist, scantype);
  216. }
  217. void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype)
  218. {
  219. struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
  220. struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
  221. u8 is_5g = (rtlhal->current_bandtype == BAND_ON_5G);
  222. if (!wifionly_cfg)
  223. return;
  224. exhalbtc_scan_notify_wifi_only(wifionly_cfg, is_5g);
  225. }
  226. void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
  227. {
  228. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  229. if (!btcoexist)
  230. return;
  231. exhalbtc_connect_notify(btcoexist, action);
  232. }
  233. void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
  234. enum rt_media_status mstatus)
  235. {
  236. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  237. if (!btcoexist)
  238. return;
  239. exhalbtc_mediastatus_notify(btcoexist, mstatus);
  240. }
  241. void rtl_btc_periodical(struct rtl_priv *rtlpriv)
  242. {
  243. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  244. if (!btcoexist)
  245. return;
  246. /*rtl_bt_dm_monitor();*/
  247. exhalbtc_periodical(btcoexist);
  248. }
  249. void rtl_btc_halt_notify(struct rtl_priv *rtlpriv)
  250. {
  251. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  252. if (!btcoexist)
  253. return;
  254. exhalbtc_halt_notify(btcoexist);
  255. }
  256. void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
  257. {
  258. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  259. if (!btcoexist)
  260. return;
  261. exhalbtc_bt_info_notify(btcoexist, tmp_buf, length);
  262. }
  263. void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
  264. {
  265. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  266. u8 extid, seq, len;
  267. u16 bt_real_fw_ver;
  268. u8 bt_fw_ver;
  269. u8 *data;
  270. if (!btcoexist)
  271. return;
  272. if ((length < 4) || (!tmp_buf))
  273. return;
  274. extid = tmp_buf[0];
  275. /* not response from BT FW then exit*/
  276. if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */
  277. return;
  278. len = tmp_buf[1] >> 4;
  279. seq = tmp_buf[2] >> 4;
  280. data = &tmp_buf[3];
  281. /* BT Firmware version response */
  282. switch (seq) {
  283. case BT_SEQ_GET_BT_VERSION:
  284. bt_real_fw_ver = tmp_buf[3] | (tmp_buf[4] << 8);
  285. bt_fw_ver = tmp_buf[5];
  286. btcoexist->bt_info.bt_real_fw_ver = bt_real_fw_ver;
  287. btcoexist->bt_info.bt_fw_ver = bt_fw_ver;
  288. break;
  289. case BT_SEQ_GET_AFH_MAP_L:
  290. btcoexist->bt_info.afh_map_l = le32_to_cpu(*(__le32 *)data);
  291. break;
  292. case BT_SEQ_GET_AFH_MAP_M:
  293. btcoexist->bt_info.afh_map_m = le32_to_cpu(*(__le32 *)data);
  294. break;
  295. case BT_SEQ_GET_AFH_MAP_H:
  296. btcoexist->bt_info.afh_map_h = le16_to_cpu(*(__le16 *)data);
  297. break;
  298. case BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE:
  299. btcoexist->bt_info.bt_supported_feature = tmp_buf[3] |
  300. (tmp_buf[4] << 8);
  301. break;
  302. case BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION:
  303. btcoexist->bt_info.bt_supported_version = tmp_buf[3] |
  304. (tmp_buf[4] << 8);
  305. break;
  306. case BT_SEQ_GET_BT_ANT_DET_VAL:
  307. btcoexist->bt_info.bt_ant_det_val = tmp_buf[3];
  308. break;
  309. case BT_SEQ_GET_BT_BLE_SCAN_PARA:
  310. btcoexist->bt_info.bt_ble_scan_para = tmp_buf[3] |
  311. (tmp_buf[4] << 8) |
  312. (tmp_buf[5] << 16) |
  313. (tmp_buf[6] << 24);
  314. break;
  315. case BT_SEQ_GET_BT_BLE_SCAN_TYPE:
  316. btcoexist->bt_info.bt_ble_scan_type = tmp_buf[3];
  317. break;
  318. case BT_SEQ_GET_BT_DEVICE_INFO:
  319. btcoexist->bt_info.bt_device_info =
  320. le32_to_cpu(*(__le32 *)data);
  321. break;
  322. case BT_OP_GET_BT_FORBIDDEN_SLOT_VAL:
  323. btcoexist->bt_info.bt_forb_slot_val =
  324. le32_to_cpu(*(__le32 *)data);
  325. break;
  326. }
  327. RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
  328. "btmpinfo complete req_num=%d\n", seq);
  329. complete(&btcoexist->bt_mp_comp);
  330. }
  331. bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv)
  332. {
  333. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  334. if (!btcoexist)
  335. return false;
  336. return btcoexist->bt_info.limited_dig;
  337. }
  338. bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
  339. {
  340. bool bt_change_edca = false;
  341. u32 cur_edca_val;
  342. u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b;
  343. u32 edca_hs;
  344. u32 edca_addr = 0x504;
  345. cur_edca_val = rtl_read_dword(rtlpriv, edca_addr);
  346. if (halbtc_is_wifi_uplink(rtlpriv)) {
  347. if (cur_edca_val != edca_bt_hs_uplink) {
  348. edca_hs = edca_bt_hs_uplink;
  349. bt_change_edca = true;
  350. }
  351. } else {
  352. if (cur_edca_val != edca_bt_hs_downlink) {
  353. edca_hs = edca_bt_hs_downlink;
  354. bt_change_edca = true;
  355. }
  356. }
  357. if (bt_change_edca)
  358. rtl_write_dword(rtlpriv, edca_addr, edca_hs);
  359. return true;
  360. }
  361. bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
  362. {
  363. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  364. if (!btcoexist)
  365. return true;
  366. /* It seems 'bt_disabled' is never be initialized or set. */
  367. if (btcoexist->bt_info.bt_disabled)
  368. return true;
  369. else
  370. return false;
  371. }
  372. void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
  373. {
  374. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  375. if (!btcoexist)
  376. return;
  377. return exhalbtc_special_packet_notify(btcoexist, pkt_type);
  378. }
  379. void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type,
  380. bool scanning)
  381. {
  382. struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  383. u8 type = BTC_NOT_SWITCH;
  384. if (!btcoexist)
  385. return;
  386. switch (band_type) {
  387. case BAND_ON_2_4G:
  388. if (scanning)
  389. type = BTC_SWITCH_TO_24G;
  390. else
  391. type = BTC_SWITCH_TO_24G_NOFORSCAN;
  392. break;
  393. case BAND_ON_5G:
  394. type = BTC_SWITCH_TO_5G;
  395. break;
  396. }
  397. if (type != BTC_NOT_SWITCH)
  398. exhalbtc_switch_band_notify(btcoexist, type);
  399. }
  400. void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type,
  401. bool scanning)
  402. {
  403. struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
  404. u8 is_5g = (band_type == BAND_ON_5G);
  405. if (!wifionly_cfg)
  406. return;
  407. exhalbtc_switch_band_notify_wifi_only(wifionly_cfg, is_5g);
  408. }
  409. struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
  410. {
  411. return &rtl_btc_operation;
  412. }
  413. EXPORT_SYMBOL(rtl_btc_get_ops_pointer);
  414. enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
  415. {
  416. struct rtl_priv *rtlpriv = rtl_priv(hw);
  417. struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
  418. enum rt_media_status m_status = RT_MEDIA_DISCONNECT;
  419. u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
  420. if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
  421. m_status = RT_MEDIA_CONNECT;
  422. return m_status;
  423. }
  424. u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
  425. {
  426. return rtlpriv->btcoexist.btc_info.btcoexist;
  427. }
  428. MODULE_AUTHOR("Page He <page_he@realsil.com.cn>");
  429. MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
  430. MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
  431. MODULE_LICENSE("GPL");
  432. MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
  433. static int __init rtl_btcoexist_module_init(void)
  434. {
  435. return 0;
  436. }
  437. static void __exit rtl_btcoexist_module_exit(void)
  438. {
  439. return;
  440. }
  441. module_init(rtl_btcoexist_module_init);
  442. module_exit(rtl_btcoexist_module_exit);